android中Retrofit源码解析(新版)
在android开发中我们原生应用发起网络请求的时候,不免需要使用android对网络请求的封装,它提供了对http协议底层的抽象,我们可以通过它提供的方法直接调用http请求。在android2.2版本及其以前的版本使用HttpClient,在android2.3版本及其之后我们使用了httpUrlConnection,而且在6.0之后android移除了httpClient,我们在高版本的API中只能使用HttpUrlConnection了。
1.1 retrofit和OkHttp的关系
但是实际情况是使用了httpUrlConnection还是很繁琐,我们还是要去考虑超时时间,服务器异常情况、数据流转为实体对象这些烦恼。所以有了对android内置的HttpUrlConnection or httpClient的包装,让我们专心处理业务逻辑。oKHttp就诞生了,android4.4版本以后都内置了oKHttp了,而我们要讨论的retrofit就是再次对okHttp的包装,丰富了很多强大的功能,比如能和Rxjava这个流行的框架结合,返回结果能回调到UI线程等。oKHttp的源码涉及到了对阻塞队列,线程池的应用,我们下一节进行探讨。
1.2 retrofit的本质
retrofit的本质就是应用了大量的设计模式对Okhttp进行了封装,加入了网络数据转换、网络请求回调、网络请求适配这几个主要的功能。它本身肯定不会去发请求的,发请求交给了OkHttp,它只对调用方式和返回结果进行处理其他的不关它的事。为什么要去研究retrofit的源码呢?因为它封装的方式解耦性很高,功能调用十分简洁,可以参照它对我们的代码也能进行改造。
1.3 源码解析(retrofit:2.4.0)
1.3.1 retrofit的创建
一起打开IDE阅读源码更虚浮!retrofit的创建是整个框架的入口,它肯定会提前准备好很多看不懂的变量进行初始化,但是这不能阻挡我们,往后看就能理解它代表的含义了。根据官方的文档,retrofit的创建使用了建造者模式。
Retrofit retrofit = new Retrofit.Builder()
//基本URL
.baseUrl("https://www.baidu.com")
//网络请求适配器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//网络请求数据转换器
.addConverterFactory(GsonConverterFactory.create())
//网络请求执行器
.client(new OkHttpClient())
.build();
所谓建造者模式就是有builder关键字的方式,就是这么简单!当然这是一个玩喜,建造者模式和我们以前 get/set 类的属性没有什么本质的区别,主要是将这些set方法全部提取出来 形成一个抽象类或者内部类,然后在一个建造者类里面去设置属性,返回一个实体类对象,列如:
public abstract Builder{
public void BulidProperty(String url);
}
public class RealBuilder extends Builder{
private RealObject object;
public void BulidProperty(String url){
object.SetProperty(url);
}
public RealObject build(){
return RealObject;
}
}
简单的思想大概是这样的,具体的我们可以看一下Retrofit中的源码。第一行代码
//第一行代码
Retrofit retrofit = new Retrofit.Builder()
很明显这个Builder是一个Retrofit的内部类,那说明建造者不是继承了抽象类,而是使用了内部类来设置属性。来看一下这个内部类,如下:
public static final class Builder {
//不知道这是什么东东先放在一边
private final Platform platform;
//很明显出现了okhttp,就知道它肯定负责去发请求
private okhttp3.Call.Factory callFactory;
// 8必多说 大家都懂
private HttpUrl baseUrl;
//很明显它是存数据转换用的,但是为什么搞一个list 懵b?
private final List<Converter.Factory> converterFactories = new ArrayList<>();
//很明显它存网络适配器用的,再次疑问这个网络适配器是什么东东?
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
//很明显他是一个回调执行器,这个有什么用呢?
private Executor callbackExecutor;
//这肯定是校验Flag目前不知道有什么用
private boolean validateEagerly;
里面看不懂的变量主要有adapterFactories存的网络适配器工厂(CallAdapter.Factory),很明显他后面会使用工厂设计模式去产生CallAdapter的对象,至于数据转换器(converter)我们都知道http请求返回来的是数据流InputStream方式的,转为Json,XML之类需要一个转换器,类似于一个double转int的工具类。
- 网络适配器的含义及其作用:网络适配器是我自己给他的定义,从命名上来看是叫:CallAdapter,Call肯定是来发请求的,Adapter忆往昔峥嵘岁月,在listView里面是界面和数据的桥梁,同理这里的CallAdapter应该是客户端和网络之间桥梁。客户端发请求的操作肯定是要通过它的。如图:
这样我们就可以清楚的看到了CallAdapter的作用了,它对OkHttp进行包装,我们调用请求方法的时候都要通过它。它同时持有了okHttp对象和回调执行器的对象,这样它通过Okhttp拿到数据之后,用回调执行器回调。
- 回调执行器:回调执行器就是在拿到数据结果之后,我们怎么返回结果的问题,主要的问题就是由于是异步请求,我们想要使用数据填充界面,需要切换到主线程。
//再看看构造函数
Retrofit retrofit = new Retrofit.Builder()
这个内部类的构造函数做了些什么内容?就一句调用自己的有参构造函数,佛了!
public Builder() { this(Platform.get());}
我们来看看这个有参构造函数和Platform类是什么东东:
//Platform类
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
//f返回一个实例就完事了
return PLATFORM;
}
//根据不同运行平台返回对应的Platforem对象
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
看到这里我们就明白了,他根据运行的平台不同来返回相应的对象,我们这里只分析 new Adnroid();看看里面有什么内容:
static class Android extends Platform {
//一个默认的回调执行器
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
//很明显 很熟悉 !创建了一个默认的CallAdapter(网络适配器),而且传入了一个回调执行器(回调执行器可以自定义,不然就是用默认绑定主线程)
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
//给力 绑定了主线程的 looper (关于Handler的详细内容可以自己查询)
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
到此我们明白了 Platfrom的作用了,它提供了一个默认的CallAdapter.Factory用来生产CallAdapter,还提供了一个绑定主线程的默认回调执行器。
再次回头看创建Retrofit的其他代码
Retrofit retrofit = new Retrofit.Builder()
//基本URL
.baseUrl("https://www.baidu.com")
//可以自定义回调执行器,否则默认回调到主线程
.callbackExecutor("xxxx")
//网络请求适配器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//网络请求数据转换器
.addConverterFactory(GsonConverterFactory.create())
//网络请求执行器
.client(new OkHttpClient())
.build();
baseUrl、add这些方法是给内部类属性赋值,我们主要来看build()方法。
public Retrofit build() {
//可见baseUrl 是必须的 使用的时候要注意
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//很明显 生产网络请求的工厂,如果你不传入自定义的okHttp对象,他会默认使用okHttpclient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//如果没有自定义,加入刚刚说过的默认调到到主线程
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//将传入到内部类callAdapter copy一份 传入到retrofit的构造函数
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//它会添加一个默认的网络适配器,这个网络适配器它持有callbackExecutor回调执行器的对象。
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//很明显类似adapterFactories 添加了一个默认,再copy一份到 retrofit的构造函数中。
List<Converter.Factory> converterFactories =new ArrayList<>(1 + this.converterFactories.size());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
//返回retrofit的实例对象就完事了
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
这里的代码都很简单,但是有几个疑问?为什么这个adapterFactories和converterFactories都是list呢,它里面都存了些什么。
- adapterFactories: 一个list集合,存储了网络适配器工厂,根据上面的代码我们可以看到它里面的内容是:先添加了自定义的、后面添加了一个默认的,总共两个元素。在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory。其他的没有用过,但是看到Rxjava我们就知道了,如果想要和Rxjava结合起来这个RxJavaCallAdapterFactory必须添加进去
//通过这个添加进去,是不是可以添加多个呢?
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//我们还可以添加
// adapterFactories里面顺序
// 自定义1-自定义2-.....默认。
addCallAdapterFactory(Java8CallAdapterFactory.create())
addCallAdapterFactory(GuavaCallAdapterFactory.create())
//converter 同理啊铁子!
.addConverterFactory(GsonConverterFactory.create())
也不会有问题,因为我们网络请求都是多种多样的,上面已经说得我们发请求就是操作CallAdapter,所以有结果返回的时候也需要通过CallAdapter。有时候我们需要Rxjava的observeable这种返回对象,有时候我们还是需要Call这种类型的返回对象,所以他需要一个list去组装对应的CalladapterFactory,Call代表了默认CallAapter返回出来的的,Observable代表了我们添加进去的RxJavaCallAdapter返回出来的。同理我们需要从CallAdapter得到想要的数据类型,converterFactories也需要多个。
@GET
//我想要Observable 需要相应的的CallAdapter
Observable<ResponseBody> download(@Url String url);
@GET
//我想要Call 默认的CallAdapter就行
//同时还需要将结果变成IModel 怎么说吧你
Call<IModel>download(@Url String url);
总结:我们清楚的看到了,retrofit的创建过程,主要的内容就是四个器的初始化,网络适配器(CallAdapter),数据转换器(conver),请求执行器(oKHttp),回调执行器(callbackExecutor)。关注点在我们发请求操作都是CallAdapter,它肯定持有其他三个的引用,就像吃鸡里面他是我们的角色,其他的是M4,头盔 药品等。
1.3.2 创建网络请求接口的实例。
对我们的的注解定义的接口方法进行解析,从而创建实例,有点迷惑?什么实例,干什么用的?我们继续往下看。
retrofit.create(RetrofitService.class);
看到这种传入.class的 ,我们可以想到肯定会用到反射。
public <T> T create(final Class<T> service) {
//校验接口正确性,是否符合注解规则
Utils.validateServiceInterface(service);
//validateEagerly 这个变量主要是作用是 是否提前加入缓存
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//很明显这里使用了动态代理模式
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//如果是java里面的基类不做处理
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 这个没什么用android平台默认返回的是false的
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//非常重要的3行代码
//解析方法的返回参数 请求参数 请求类型等
ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
//很明显OkHttp就知道他是一个网络执行器
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//很明显他 肯定是调用了callAdapter
return serviceMethod.adapt(okHttpCall);
}
});
}
这里的代码稍微有一丢丢复杂,主要理解代理模式。代理代理,不知道大家是否知道代购。比如你想买一件surpene的衣服,当然superme肯定买不起,只能买买faker。又拉下不脸,找了一个代购。
代理类会获取被代理类的所有方法,并返回一个被代理类的对象,这个对象就是虚拟的你,通过它去购买需要的商品。Proxy.newProxyInstance(xxx)是固定用法,只要传入xxx.class参数就行。
//固定格式
ClassLoader classLoader =Shop.class.getClassLoader();
//固定格式,三个参数,传入Shop.class参数,获取所有方法,返回代理对象。
Shop shopProy = (Shop) Proxy.newProxyInstance(classLoader, new Class[]{IShop.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//回调原来类的方法,该怎么做就怎么做
Object result = method.invoke(proxy,args);
//也可以自己实现 不回调原来的方法。
//.............................
return result;
}
});
这里的Invoke方法,就是代理方法的实现,method.invoke()代表了回调原来的方法,这里也可以自己去实现方法,只要返回对应的类型。代理模式优点就是提供了一个拦截接口,不管你什么方法调用都会先进入Invoke。具体内容可以学习JAVA反射来加深印象。
.........................................
//validateEagerly 这个变量主要是作用是 是否提前加入缓存
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//很明显这里使用了动态代理模式
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//.............................
//非常重要的3行代码
//解析方法的返回参数 请求参数 请求类型等 关键代码1
ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
//很明显OkHttp就知道他是一个网络执行器 关键代码2
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//很明显他 肯定是调用了callAdapter 关键代码3
return serviceMethod.adapt(okHttpCall);
}
回到代理创建接口实例的方法中,我们创建接口的时候都是只写了方法名,没有具体的实现,所以在代理对象并不能回调,它只能自己去实现而且还要返回你要想的结果类型。苦b啊!
public interface RetrofitService {
//没有方法体 只有名字 怎么破(只能靠retrofit给我们实行)
@GET
Observable<ResponseBody> download(@Url String url);
// 没有方法体,只有名字 怎么破
@GET
Call<ResponseBody>download(@Url String url);
}
在retrofi中,利用了ServceMehod这个类来进行实现方法体,它会获取到接口方法的参数,返回值类型,请求方式等所有参数。看一下关键代码1,loadServiceMethod()!!
ServiceMethod<?, ?> loadServiceMethod(Method method) {
//搞个缓存啊 美滋滋
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//缓存里面没有,说明是第一次调用,安排一下,并且加入缓存
result = new ServiceMethod.Builder<>(this, method).build();//我只是一个建造者,传入了retrofit的对象,拥有了adapterFactorese等所有属性。
serviceMethodCache.put(method, result);
}
}
return result;
}
代码很简单,对调用的方法做一个缓存,第一次调用的时候才会去解析方法,其他情况下会使用缓存。同时我们也应该知道validateEagerly这个Flag的作用了,如果你设置为true会创建动态代理对象的时候将所有的方法解析缓存,否则就只会在第一次调用的时候去缓存。
虽然已经知道了ServiceMethod会对我们请求的方法进行一顿瞎x操作,各种解析分析组装,但是我们还要要去看看实况,它采用了建造者模式(builder),直接看.build()方法。
public ServiceMethod build() {
..........................................//
//根据返回值类型,在adapterFactories的list里面去寻找CallAdapter,如observeable,就会寻找RxjavCallAdapter.Factory 工厂模式产生CallAdapter 的对象。
callAdapter = createCallAdapter();
//获取返回值中的数据类型
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
//根据CallAdapter的返回的值中的数据类型(如: Call<Bean> download(), 就会根据 ‘ Bean’去寻找Gson转换器)去遍历converterList找转换器,Converter 的对象。
responseConverter = createResponseConverter();
//遍历方法中的所有注解 一顿操作保存起来。
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
int parameterCount = parameterAnnotationsArray.length;
// 保存请求参数的工具类
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
..................///
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
..................//
//遍历方法参数中的所有注解和变量到parameterHandlers
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
.......................//
//返回一个 ServiceMethod的实例
return new ServiceMethod<>(this);
}
主要作用是根据方法的返回值类型,获取相应的网络适配器、数据转换器以及拆卸参数类型等保存在parameterHandlers中。列如:createCallAdapter会去遍历callAdapterFactories找到相应的callAdapter。
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
//.......................................................
//根据返回值遍历callAdapterFactories
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
// get返回了一个CallAdapter对象
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
//这里假设我们返回值是 Call<Bean> 类型的 ,默认的ExecutorCallAdapterFactory会被匹配到。看看它的get方法
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
//给力呀 铁子 返回了一个 CallAdapter对象
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
// 我就是方法体啊铁子
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
其中Calladapter中的adapt方法就是方法体了。后续详细介绍这个CallAdapter类。
根据关键代码1, loadServiceMethod()返回了一个ServiceMethod的实例,它里面包含了你调用方法的所有信息,包含注解,参数类型,参数名,返回值类型等,来看看它里面主要的属性:
final class ServiceMethod<R, T> {
.............................//
//这个是Okhttp的工厂实例,用来生产请求call的
private final okhttp3.Call.Factory callFactory;
//桥梁callAdapter 实例 发请求都是它在操作okhttp
private final CallAdapter<R, T> callAdapter;
// 8 必再说
private final HttpUrl baseUrl;
//数据转换器实例
private final Converter<ResponseBody, R> responseConverter;
.......................//
//存储请求参数的集合
private final ParameterHandler<?>[] parameterHandlers;
到此Retrofi已经实现了高度的解耦,定义一个请求方法,我只想调用一下得到结果,至于怎么请求的,和怎么转换结果都不想关注。retrofit在这里使用了外观模式,只用定义方法入口(Retrofit.create(YourInterface.Class)),减少了对内部细节的依赖,里面发生了变化,我们也不用担心。
继续看关键代码2:
//很明显这里使用了动态代理模式
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//.............................
//非常重要的3行代码
//解析方法的返回参数 请求参数 请求类型等 关键代码1
ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
//很明显OkHttp就知道他是一个网络执行器 关键代码2
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//很明显他 肯定是调用了callAdapter 关键代码3
return serviceMethod.adapt(okHttpCall);
}
将servcieMethod传入到oKhttpCall,serviceMethod已经把请求参数拆卸下来存储在了parameterHandlers中,OkHttpCall会取出参数类型和值进行组装请求。
final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T, ?> serviceMethod;//含有所有网络请求参数类型等等
private final @Nullable Object[] args;//请求参数的值
private volatile boolean canceled;//取消请求Falg
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;//真正发请求的Okhttp
............................................//
}
OkHttpCall里面有了okhttp对象,使用它来进行发请求操作,具体我们往下看。
关键代码3:
//很明显他 肯定是调用了callAdapter 关键代码3
return serviceMethod.adapt(okHttpCall);
// 在ServiceMethod中adapt 调用了callAdapter
final class ServiceMethod {
..................................//
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
...............................//
}
将生产好的Call对象传入到adapter中,然后开始实现方法体.
这里结合实例来看:
//我想要Call类型的返回值,使用默认CallAdapter的就行了
@GET
Call<Model>download(@Url String url);
//使用 mRetrofitService.downloadADfile(xxx),就是在调用 serviceMethod.adapt(okHttpCall);
Call<Model> call = mRetrofitService.downloadADfile("www.kawayi.com");
我们在这里的 "call = "返回的是什么呢?来看一哈肯定很简单。
//根据刚返回类型'Call' 遍历CallAdapterFactories循环出得到默认CallAdapter
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
//返回了一个ExecutorCallbackCall对象 来看一哈
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
很显然返回了一个ExecutorCallbackCall对象,ExecutorCallbackCall内容并不是很复杂。
//这里是ExecutorCallbackCall 继承了Call
static final class ExecutorCallbackCall<T> implements Call<T> {
//回调执行器,有自定义就用自定义否则就会使用platform这个对象生产出绑定主线程的回调
final Executor callbackExecutor;
//这里传入的是OkhttpCall
final Call<T> delegate;
//构造函数,传入了OkhttpCall,和回调执行器,装饰模式安排安排
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
//执行异步请求
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
//回调执行器 切换线程
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
.......................//
}
代码很简单,显然CallAdapter的内部类ExecutorCallbackCall拥有okhttp和回调执行器,所有的一切操作都在是它在执行了。这里使用了装饰模式,加强了okhttCall。装饰模式:就是不改变类文件和使用继承的情况下,动态地扩展一个对象的功能,是一种代替继承的方案。
C和A都继承了B,但C里面有A的对象,所以他可以调用A的方法,而且能添加一些A中没有的功能。如:
static final class ExecutorCallbackCall<T> implements Call<T> {
......................................//
//ExeCutorCallbackCall和delegate都继承了Call,但ExeCutorCallbackCall有回调执行,取消请求这些功能,得到了加强。
final Call<T> delegate;
这里的delegate得到了加强,拥有了切换线程的功能。
总结:retrofit.create(RetrofitService.class),使用了动态代理创建RetrofitService对象,并且对它接口中的方法进行了实现,根据返回值的类型,寻找CallAdapter和converter并且拆卸请求参数,组装请求,最后返回了Call的对象。
1.3.3 返回值执行网络请求
根据实例来看源码:
//我想要Call类型的返回值,使用默认CallAdapter的就行了
@GET Call<Model>download(@Url String url);
//实际上就是在调用serviceMethod.adapt(okHttpCall);
Call<Model> call = mRetrofitService.downloadADfile("www.kawayi.com");
//发一个异步请求。
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
根据刚刚分析的代码可以知道,返回的call对象是ExecutorCallbackCall的实例,enque执行异步请求的,就会调用ExecutorCallbackCall的enque方法。
//这里是ExecutorCallbackCall 继承了Call
static final class ExecutorCallbackCall<T> implements Call<T> {
//执行异步请求
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
//okhttpCall去执行请求,奥给力。
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
//这只是一个回调执行器,切换线程
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
.......................//
}
代码中可以看到,我们传入的okHttpCall(serviceMethod.adapt(okHttpCall))会调用okttp去执行请求,并且用回调执行器回调okhttp返回的数据数据。
下面来看看okHttp具体是怎么处理的
final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T, ?> serviceMethod;//含有所有网络请求参数类型等等
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;//真正发请求的Okhttp
............................................//
//发一个异步请求。实际上是okhttp操作
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
//okhttp的实例
okhttp3.Call call;
..............................................\\
call = rawCall = createRawCall() ;//拿到parameterHandlers的参数,组装一个请求
...........................................\\
//真正的发一个请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//使用数据转换器,转换一下就完事了。
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
//回到到对应的CallbackCall中,默认是ExecutorCallbackCall
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
OkhttpCall首先先对请求进行一个组装,然后赋值给一个okhttp.Call的对象。通过call对象去发起请求,中间有异常超时对应的处理,拿到正确的请求结果之后,解析数据,回调到对应的CallbackCall,默认是ExecutorCallbackCall,最后在ExecutorCallbackCall中使用回调执行器再次回调。
2.1 总结
1、Retrofit对oKHttp层层封装,利用动态代理模式,实现接口定义的方法。
2、根据返回值类型匹配对应的CallAdapter,converter,这里使用了策略模式。在对应的callAdapter中使用了装饰器模式并且返回了一个加强的Call对象。
3、利用返回的Call对象来发请求,利用内部包装的OkHttp对象,执行请求。结果返回之后,converter解析数据,经过层层回调,到最后回调执行器切换线程。
参考文献
[1]刘望舒.Android进阶之光