Retrofit源码解析(一)
Retrofit源码解析(三)
上一篇中大致对比了okhttp和retrofit发送请求的大致流程,了解okhttp的工作流程对掌握retrofit是非常重要的。本篇继续讲解retrofit的内部构成。retrofit使用Builder模式完成构建,通过Builder模式开发者可以配置常用的GsonConvertFactory完成json数据实例化,也可以添加RxJava2CallAdapterFactory进行自定义请求,最终这些额外的配置都被保存在Retrofit的实例当中。下面先来看Retrofit的属性都有哪些:
public final class Retrofit {
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
···
}
serviceMethodCache
serviceMethodCache是一个存储ServiceMethod的map。ServiceMethod是一个非常重要的类,我们在接口中定义的每一个请求方法最终都会在运行时被解析,方法注解中的所有信息都会被保存在一个ServiceMethod对象中。当方法被调用时,retrofit通过动态代理拿到运行时Method对象,根据Method对象构建一个ServiceMethod对象,并调用ServiceMethod的invoke方法完成最终的请求。
callFactory
callFactory是Okhttp中定义的接口,并不是retrofit定义的。他的作用就是创建网络请求的真正的Call对象。通过引用接口,开发者就可以注入自己的默认实现,达到多态的效果。他有一个默认的实现类大家都不会陌生:OkHttpClient。上一篇中我们说过retrofit是通过okhttp完成的网络请求,实际的体现就是这里。
package okhttp3;
public interface Call extends Cloneable {
···
interface Factory {
Call newCall(Request request);
}
}
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
···
}
baseUrl
这个类比较简单,就是用来保存baseUrl,不再多说。
converterFactories
Converter.Factory是retrofit中定义的类。我们知道在okhttp的回调方法中,最终的返回值是一个固定的类型Response。通过response.body()方法可以获取到ResponseBody对象进而通过responseBody.string()方法获取body的实际内容,这些类型都是固定的需要我们自己对返回结果进行手动解析。
但是在retrofit中,在数据请求成功回调后,retrofit会在converterFactories列表中根据接口中方法的返回值Call<T>的泛型T,选择一个合适的转化器工厂,自动进行类型转化.
package retrofit2;
public interface Converter<F, T> {
@Nullable
T convert(F value) throws IOException;
abstract class Factory {
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
···
}
}
Converter.Factory有一个默认的实现类BuiltInConverters,在创建retrofit的时候会永远把BuiltInConverters放在converterFactories列表的第一个。BuiltInConverters是 retrofit 提供的默认数据转化器工厂,他的转化只是将ResponseBody直接缓存返回,并没有其他额外的工作。所以如果在接口中定义的方法的返回值是Call<ResponseBody>的时候,这时候retrofit就会使用BuiltInConverters进行数据转化。
如果我们又向retrofit中添加了GsonConvertFactory,此时接口中方法的返回值就可以写成这样Call<User>,这时泛型不再是ResponseBody而是User,retrofit就会选择使用GsonConvertFactory进行数据转化。然后在回调中我们就可以直接获取到User对象了。
callAdapterFactories
这里retrofit使用适配器模式对最原始的okhttp中的Call对象进行一层层的装饰,每一层的包装都可以完成一些自定义的对Okhttp的Call的操作,比例:线程切换。在构建ServiceMethod的时候,retrofit会根据接口中定义方法的返回值类型去callAdapterFactories中查找符合要求的adapter工厂。
CallAdapter.Factory也是retrofit提供的一个抽象的工厂类。
package retrofit2;
public interface CallAdapter<R, T> {
···
abstract class Factory {
···
}
}
DefaultCallAdapterFactory是该类的默认实现,在构建retrofit时会自动添加到callAdapterFactories列表中。DefaultCallAdapterFactory只会处理接口中方法返回值为Call<T>的类型。所以在默认情况下我们必须将接口中方法的返回值定义为Call<T>类型,否则会抛出异常。
如果我们又为retrofit添加了RxJava2CallAdapterFactory,那么此时接口中定义的方法就可以返回Observable<T>了,然后我们就可以使用RXJava的方式进行请求。但是此时callAdapterFactories列表中只有DefaultCallAdapterFactory和RxJava2CallAdapterFactory两个工厂,也就是说现在接口中方法可以接受的返回值有Call<T>和Observable<T>两种类型。如果你写一个String类型,那么同样会抛出异常。
callbackExecutor
就是有个普通的线程池,他的默认实现是一个通过Handler在主线程执行的类,retrofit默认的线程调度就是通过这个线程池。
package retrofit2;
class Platform {
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
总结
可以看到retrofit的设计处处都透露着设计模式和代码的基本原则。在retrofit中引用了三种抽象的工厂,开发人员可以注入自己的工厂实现。用装饰器模式对okhttp的Call进行自定义的处理达到线程切换的效果、通过动态代理执行网络请求等等。本篇从整体介绍了retrofit内部成员的职责,下一篇中将开始系统的讲解retrofit是如何发送网络请求到数据解析的整个流程。