十分鐘教你手擼一個簡單的Retrofit demo
眾所周知,retrofit框架是square公司旗下的著名的http請求框架,今天我們來理一理它的主要邏輯,并寫一個demo,這里涉及到java中注解,反射,泛型等知識點和構建者模式、動態代理,和我一起來一探究竟吧,
Retrofit的具體用法請自行百度,下面是關鍵的三行代碼
//利用構建者模式實體化Retrofit
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://restapi.amap.com/").build();
//通過動態代理生成介面的實體物件,并實作介面中定義的方法;
apiService = (ApiService) retrofit.create(ApiService.class);
//代理物件去做http請求
Call call = (Call) apiService.get("110101","ae6c53e2186f33bbf240a12d80672d1b");
先想一想做http請求,我們需要什么?需要域名,請求方式,請求引數,嗯,還需要Okhttp
實作Retrofit第一步
構建MyRetrofit類,在里邊兒定義一個內部Builder類,構建者模式是將一個復雜的物件一步一步建立起來,然后在Builder型別中baseUrl方法準備好域名,callFactory準備好OKHttp ,build()方法將獲得的引數傳入MyRetrofit構造方法,回傳MyRetrofit實體物件,
public class MyRetrofit {
?
public final HttpUrl baseUrl;
public final Call.Factory factory;
?
public MyRetrofit(HttpUrl baseUrl, Call.Factory factory){
this.baseUrl = baseUrl;
this.factory = factory;
}
?
public static final class Builder{
private HttpUrl baseUrl;
private Call.Factory factory;
?
public Builder baseUrl(String url){
if(url != null){
baseUrl = HttpUrl.get(url);
}
return this;
}
public Builder callFactory(Call.Factory factory){
if(factory != null){
this.factory = factory;
}
return this;
}
?
public MyRetrofit build(){
if(this.factory == null){
this.factory = new OkHttpClient();
}
return new MyRetrofit(baseUrl,factory);
}
}
}
實作Retrofit第二步
通過介面創建代理物件, 并在invoke的回呼中實作apiService中定義的方法,代理模式是類似于中介代理的某項服務,類似于租房,你不需要知道房東是誰,只需要找中介就能租,靜態代理是租房找租房中介,留學找留學中介,相親找媒婆;而動態代理就很牛了,不管是租房,留學還是相親都可以找這個中介,即靜態代理是一個代理功能對應一個代理類,動態代理是多個代理功能對應一個代理類,下面是生成http請求的動態代理類,Proxy.newProxyInstance()中通過介面生成動態代理類,newProxyInstance()方法中先對interfaces介面做拷貝,再根據拷貝的介面和類加載器生成代理類,最后獲取代理類的構造方法,再回傳由構造方法實體化的代理物件,在InvocationHandler回呼的invoke方法中實作http請求邏輯,具體的實作方式交給ServiceMethod,
public <T> T create(Class<T> service){
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ServiceMethod serviceMethod = loadServiceMethod(method);
return serviceMethod.invoke(args);
}
});
}
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
?
//對interfaces介面做拷貝
final Class<?>[] intfs = interfaces.clone();
// Android-removed: SecurityManager calls
/*
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
*/
?
/*
* Look up or generate the designated proxy class.
*/
//根據拷貝的介面和類加載器生成代理類
Class<?> cl = getProxyClass0(loader, intfs);
?
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
// Android-removed: SecurityManager / permission checks.
/*
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
*/
?
//獲取代理類的構造方法
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
// BEGIN Android-changed: Excluded AccessController.doPrivileged call.
/*
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
*/
?
cons.setAccessible(true);
// END Android-removed: Excluded AccessController.doPrivileged call.
}
//回傳由構造方法實體化的代理物件
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
實作Retrofit第三步
在第二步利用動態代理獲取代理物件的create方法回呼中的invoke方法中實作http請求,這一步講講ServiceMethod如何實作http請求;
ServiceMethod要根據create傳入的api請求介面
public interface Apitest1 {
@POST("/v3/weather/weatherInfo")
Call postTest1(@Field("city") String city, @Field("key") String key);
?
@GET("/v3/weather/weatherInfo")
Call getTest1(@Query("city") String city, @Query("key") String key);
}
通過反射獲取Apitest1介面中宣告方法的注解和方法引數上的注解獲得請求方式,請求url,請求引數等,利用OkHttp發送這次請求,
ServiceMethod類的物件也是通過構建者模式建立起來的,在ServiceMethod類中定義內部類Builder,
定義Builder的構造方法,傳參Method和MyRetrofit 在構造方法中做兩件事情
第一 ,通過反射method.getDeclaredAnnotations()獲取方法上的注解,得到請求方式(post or get),請求url,
第二,通過method.getParameterAnnotations()獲得方法引數的注解,得到請求引數(這里的請求引數是 @Query("city")中的city),然后根據不同注解型別將獲取的注解值放入不同的ParamHandler中,Field型別放FieldParamHandler,Query型別放QueryParamHandler中,
最后build()方法回傳ServiceMethod實體,
在invoke方法中傳入引數為Apitest1宣告的函式中的引數,再將引數和ParamHandler陣列構建成請求體formBody,最后由url,formBody和請求方式創建request請求,最后用OKhttp框架中factory.newCall(request)執行請求,
?
public class ServiceMethod {
private static HttpUrl.Builder formBuilder;
private static FormBody.Builder formBodyBuilder;
private Call.Factory factory;
private HttpUrl baseUrl;
private String relativeUrl;
private Boolean hasBody;
private String httpMethod;
private ParamHandler[] paramHandlers;
?
public ServiceMethod(Builder builder){
this.factory = builder.factory;
this.baseUrl = builder.baseUrl;
this.relativeUrl = builder.relativeUrl;
this.hasBody = builder.hasBody;
this.httpMethod = builder.httpMethod;
this.paramHandlers = builder.methodParamHandler;
}
?
public Object invoke(Object[] args) {
for (int i = 0; i < paramHandlers.length; i++) {
paramHandlers[i].apply(this, (String) args[i]);
}
if(formBuilder == null){
formBuilder = baseUrl.newBuilder(relativeUrl);
}
HttpUrl url = formBuilder.build();
if(formBodyBuilder == null){
formBodyBuilder = new FormBody.Builder();
}
FormBody formBody = null;
if(hasBody){
formBody = formBodyBuilder.build();
}
Request request = new Request.Builder().url(url).method(httpMethod,formBody).build();
return factory.newCall(request);
}
?
public static void addParamToFormBody(String key,String value){
if(formBodyBuilder == null){
formBodyBuilder = new FormBody.Builder();
}
formBodyBuilder.add(key,value);
}
?
public void addParamToQueryFormBody(String key, String value){
if(formBuilder == null){
formBuilder = baseUrl.newBuilder(relativeUrl);
}
formBuilder.addQueryParameter(key,value);
}
?
public static class Builder{
private ParamHandler[] methodParamHandler;
private Annotation[] methodOverAnnotations;
private Annotation[][] methodAnnotations;
private Call.Factory factory;
private HttpUrl baseUrl;
private String relativeUrl;
private Boolean hasBody;
private String httpMethod;
public Builder(Method method,MyRetrofit myRetrofit){
this.methodOverAnnotations = method.getDeclaredAnnotations();
this.methodAnnotations = method.getParameterAnnotations();
this.factory = myRetrofit.factory;
this.baseUrl = myRetrofit.baseUrl;
for (Annotation methodOverAnnotation : methodOverAnnotations) {
if(methodOverAnnotation instanceof POST){
this.hasBody = true;
this.httpMethod = "POST";
this.relativeUrl = ((POST) methodOverAnnotation).value();
}else if(methodOverAnnotation instanceof GET){
this.httpMethod = "GET";
this.hasBody = false;
this.relativeUrl = ((GET) methodOverAnnotation).value();
}
?
}
int length = methodAnnotations.length;
methodParamHandler = new ParamHandler[length];
for (int i = 0; i < length; i++) {
Annotation[] annotations = methodAnnotations[i];
for (Annotation annotation : annotations) {
if(annotation instanceof Field){
methodParamHandler[i] = new ParamHandler.FieldParamHandler(((Field) annotation).value());
} else if(annotation instanceof Query){
methodParamHandler[i] = new ParamHandler.QueryParamHandler(((Query) annotation).value());
}
}
}
}
?
public ServiceMethod build(){
return new ServiceMethod(this);
}
?
}
}
?
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/226830.html
標籤:java
