我们知道,Retrofit进行网络请求的工作本质是由OkHttp完成的,而Retrofit负债网络请求接口的封装。本文详解Retrofit源码在请求时使用的动态代理模式、工厂模式、静态代理模式、外观模式和对请求结果进行线程切换。
我们使用Retrofit的方式如下:
1、动态代理模式:
看Retrofit的create方法:
可知,该方法返回一个通过Proxy.newProxyInstance()创建的动态代理对象wanAndroidService,而调用动态代理对象wanAndroidService的getProjectArticle(1, 1)会调用invoke方法。
看loadServiceMethod方法:
Annotation[] methodAnnotations、Type[] parameterTypes和 Annotation[][] parameterAnnotationsArray分别是方法的注解,方法的参数类型,方法参数注解的数组。
parseMethodAnnotation()方法就是解析方法的注解:
反射耗性能,也就是new ServiceMethod.Builder(this.method)耗性能,那么Retrofit是如何解决这个反射带来的性能问题的?答案是缓存,也就是将实例化得到的ServiceMethod对象缓存起来:
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
而且用于缓存的容器还是个使用了LRU算法的LinkedHashMap。
2、工厂模式:
再看前面截图中Retrofit的第561行build()方法里,adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor))
是,platform的defaultCallAdapterFactory方法返回ExecutorCallAdapterFactory对象,所以platform.defaultCallAdapterFactory(callbackExecutor)是把callbackExecutor传入ExecutorCallAdapterFactory的构造方法,将实例化得到的ExecutorCallAdapterFactory对象存入List<CallAdapter.Factory> adapterFactories,然后把adapterFactories 传入Retrofit的构造方法,从而称为Retrofit的成员变量。
ExecutorCallAdapterFactory如下:
它本身是Factory的子类,这个工厂是通过get方法来生产它的产品—CallAdapter对象,CallAdapter有个adapt的方法,通过这个adapt方法可返回一个ExecutorCallbackCall对象来。
3、静态代理模式
先说结论:前述的ExecutorCallbackCall是OkhttpCall的代理类(下面有详细分析),用户调用生成的动态代理对象wanAndroidService的getProjectArticle(1,1)方法返回的就是ExecutorCallbackCall这个Call对象,然后用户再调用该对象的enqueue方法,该方法会调用OkhttpCall的enqueue方法,在OkhttpCall的enqueue方法里通过外观模式调用Okhttp的相应方法从而进入网络请求的流程。现在论证这个结论:
用户调用wanAndroidService.getProjectArticle(1, 1)就会执行InvocationHandler的invoke方法,执行return serviceMethod.callAdapter.adapt(okHttpCall)并且,其中serviceMethod.callAdapter会调用到Rrtrofit的CallAdapter<?> nextCallAdapter(…)方法:
其实就是通过前述的ExecutorCallAdapterFactory的get方法来生产一个CallAdapter对象产品,所以,serviceMethod.callAdapter.adapt(okHttpCall)其实是调用CallAdapter的adapt方法返回了一个OkhttpCall的代理对象—ExecutorCallbackCall对象。
注意这个adapt方法把OkhttpCall对象转入ExecutorCallbackCall的构造方法,而OkhttpCall和ExecutorCallbackCall都实现了Call接口,所以ExecutorCallbackCall是OkhttpCall的静态代理类。用户调用projectArticle.enqueue其实就是执行ExecutorCallbackCall对象的enqueue方法:
第75行的delegate.enqueue就是通过静态代理调用OkhttpCall的queue方法(下面有详述),然后第77行就是转换成主线程。
4、外观模式
先看OkHttpCall的queue方法:
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
**//声明okhttp3.Call call变量
okhttp3.Call call;**
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
...
if (call == null && failure == null) {
try {
**//得到okhttp3.Call call对象
call = rawCall = createRawCall();**
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
...
**call.enqueue(new okhttp3.Callback()** {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
...
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
...
}
...
}
});
}
可知,在OkhttpCall类中的enqueue方法中,创建个okhttp3.Call call对象。然后call.enqueue(new okhttp3.Callback() {…})
所以很明显,这里封装okhttp,即调用okhttp3.Call对象的enqueue方法进行请求,这是外观设计模式。
5、对请求的结果切换到主线程进行处理:
在Retrofit类的build()函数中,使用了看似是线程池的东西,来看这个platform是什么,已经它的defaultCallbackExecutor()方法如何返回callbackExecutor:
可知,执行defaultCallbackExecutor()方法可得到实现了Executor接口的MainThreadExecutor对象,执行该对象的execute方法,就是执行Main线程的handler的post方法,从而可以达到子线程切换到主线程。