阅读本篇博客之前,建议读者先按顺序读一读博主的下面几篇博客: Retrofit源码解析之请求流程概述 Retrofit之Converter简单解析 Retrofit之OkhttpCall执行原理详解 根据前几篇博客我们知道,Retrofit常规使用方法可以用如下几行代码表示:
MyApi api = retrofit.create(MyApi.class);
/*获取ExecutorCallbackCall*/
Call call= api.getData();
/*执行同步请求*/
Resonse response = call.execute();
/*获取真实数据*/
T data = response.body();
上述代码中的call对象的实例为ExecutorCallbackCall(常规使用情况,没考虑跟Rx结合的情况),它的主要作用就是代理了OkhttpCall执行网络execute/enqueue(同步/异步)请求,同时将异步的回调通过Handler转接到Android主线程调度队列里面。(详见 Retrofit源码解析之请求流程概述).
同时上述代码api.getData()的执行是通过代理对象的invoke方法执行的,主要做了三个工作: 1、将getData()方法的Method对象,及其方法注解,方法参数,方法参数注解等信息封装成一个ServiceMethod对象。 2、根据骤1生成的ServiceMethod对象,创建一个OkhttpCall对象 3、调用callAdapter.adpte(okhttpCal)方法返回Call
完成api.getData()的执行。 其invoke方法如下所示:
//Retrofit的create方法(删除了部分与本文无关的代码)
public T create(final Class service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[] { service },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, @Nullable Object[] args)
//创建SeriviceMethd对象
ServiceMethod serviceMethod =
(ServiceMethod) loadServiceMethod(method);
//创建OkHttpCall对象
OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
//返回ExecutorCallbackCall
return serviceMethod.adapt(okHttpCall);
}
});
}//end create
//ServiceMethod的adapt方法:
T adapt(Call call) {
return callAdapter.adapt(call);
}
问题来了,既然ExecutorCallbackCall只是OKHttpCall的一个代理类,比如该类的execute()方法内部t就是直接调用了OKHttpCall的execute方法而已。那么为什么还要这个callAdapter呢?完全可以将invoke方法改成如下所示:
//修改后的invoke方法
public Object invoke(Object proxy, Method method, @Nullable Object[] args){
//创建ServiceMethod
ServiceMethod serviceMethod =
loadServiceMethod(method);
//直接返回OkHttpCall
return new OkHttpCall(serviceMethod, args);
}
改动后的代码在执行api.getData()后返回的Call
就是OKhttpCall了,同样我们也可以拿到正确的数据.那么我们可以设想一下为什么Retrofit还要设计一个CallAdapter接口呢?
回答这个问题之前,先来说一个客观事实,Retrofit真正使用Okhttp进行网络请求的就是OkHttpCall这个类。上面改动后的invoke方法确实能满足要求,因为返回的就是OkHttpCall这个对象,直接操控这个对象就可以完成网络请求。
但是改动后的代码带来的后果之一就是:因为OkHttpCall实现了Call接口,API Service方法的返回值必须是Call
类型,直观表现如下所示:
interface MyApi {
Call loadA();
Call loadB();
Call loadC();
}
那么如果我们想要返回的不是Call呢?比如RxJava的Observable,这种情况下该 怎么办呢? 适配器模式在此发挥了其应用的作用!!!
将网络请求的核心类OkHttpCall进行适配,你需要什么类型的数据就通过适配器适配,返回适配后的对象就是了。Retrofit适配器的接口设计如下:
//R原始类型,T适配后的类型
public interface CallAdapter {
//泛型包裹的真实对象类型,比如Call则就是A的Type对象
Type responseType();
//Returns an instance of {@code T} which delegates to {@code call}.
//返回一个T类型来代理Call,在这里可以先认为是OkHttpCall
T adapt(Call call);
}
这么一来,我们的API方法的返回类型就不再仅仅限制于Call这个类型了,比如你想返回的是一个自定义类型,该类型暂且命名为MyDefineType,那么就可以简单的这么做:
//自定义适配器
class MyCallAdapter implement CallAdapter {
public MyDefineType adapt(Call call) {
return new MyDefineType(call);
}
}
class MyDefineType {
//代理OkHttpCall
private final Call delegate;
MyDefineType(Call call){
this.delegate = call;
}
public R execute() {
Reponse response = delegate.execute();
return response.body();
}
}
有了上面的Call适配器之后,我们就可以扩展我们API:
interface MyApi {
Call loadA();
Call loadB();
Call loadC();
MyDefineType loadD();
}
此时loadD的调用直接就是:
DBean data = myApi.loadD().execute();
正式这种CallApdate接口的设计,使得我们在使用Retrofit的时候可以自定义我们想要的返回类型。此接口的设计也为RxJava的扩展使用做了很好的基础!!!
从上面的讨论可以得出如下结论:每个Api方法的返回类型都需要一个CallAdapter对象与之对应。可以用下图来表示:
再结合OkhttpCall和前面几篇文章讲解的Converter的话,上面的图示就可以扩展为如下所示:
其实通过上图以及Retrofit代理类的invoke方法可以看出一个问题,问题就是Retrofit硬编码的方式强制使用了OkhttpCall(注意OkhttpCall实现了Call接口),而没有用Call接口的自定义实现类:
public Object invoke(Object proxy, Method method, @Nullable Object[] args)
//创建SeriviceMethd对象
ServiceMethod serviceMethod =
(ServiceMethod) loadServiceMethod(method);
//创建OkHttpCall对象
OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
//返回ExecutorCallbackCall
return serviceMethod.adapt(okHttpCall);
}
如果考虑到扩展性的话,上面初始化OkhttpCall的代码的代码应该这么写:
//通过工厂对象类获取Call
Call call = callFactory.createCall(params);
通过工厂的形式获取Call接口的实例,而不是直接硬编码,这样就可以带来很好的扩展性.其实Retrofit设计Call的初衷应该就是为了这个扩展。但是目前好像还没有很好的实现,可能后期会有所表示吧。那么理论上的Retrofit可能就会变成如下所示了: 那么如何判定选取哪个CallAdapter来工作呢?Retrofit是怎么检索出需要哪一个CallAdapter的,下面就来仔细分析这个问题:
说道CallAdapter检索,顾名思义,就是需要从一堆共性的东西里查找某一个合适的对象。在Retrofit中就有CallAdapter的集合:
final List callAdapterFactories;
这个集合不是List
的集合,而是其工厂的对象的集合。工厂对象的目的就是用来创建CallAdapter对象的,且根据上文我们知道每个Api方法的返回类型都需要一个CallAdapter对象与之对应,对这句话进行需求分析来看就是根据返回类型返回一个CallAdapter对象。伪代码用如下:
if(returnType == A){
return CallAdapterA();
}else if(returnType == B){
return CallAdapterB()
}else if(returnType==C) {
return CallAdapterC();
}else if(...){
...
}else{
return DefaultCallAdapter();
}
这种代码看着就很蛋疼,所以此时工厂模式起到了很好的作用。该CallAdapter.Factory代码主要代码如下:
abstract class Factory {
//根据returnType等信息返回一个与之对应的CallAdaper
public abstract @Nullable CallAdapter get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
}
既然Retrofit提供了callAdapterFactories,其在Retrofit.Buider里的构建过程在此也简单的了解一下,具体的添加Factory的代码在Builder中如下所示:
private final List callAdapterFactories = new ArrayList();
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
adapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
那么Builder在构建Retrofit对象的时候就如下所示了:
public Retrofit build() {
//省略部分代码
//添加callAdapter的工厂对象
List callAdapterFactories = new ArrayList(this.callAdapterFactories);
//添加一个默认的CallAdapter:博文后面会有说明
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//省略部分代码
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
代码分析到现在,CallAdapter的工厂对象都放到了一个List集合里面,剩下的就是怎么从这个集合里检索出所对应的CallAdater了。
根据之前博客的分析,我们知道在执行一个api方法的时候都会构建一个ServcieMethod对象,该对象表示一个api方法的封装,同时该对象有个createCallAdapter方法,该方法的主要作用就是根据对应api方法的返回值来从上述集合中获取一个合适的CallAdapter:
private CallAdapter createCallAdapter() {
Type returnType = method.getGenericReturnType();
//省略部分代码
Annotation[] annotations = method.getAnnotations();
return (CallAdapter) retrofit.callAdapter(returnType, annotations);
}
注意createCallAdapter方法的调用实在ServiceMethod.Builder的buid方法中完成的:
public ServiceMethod build() {
callAdapter = createCallAdapter();
}
最终会调用retrofit的callAdapter对象:
public CallAdapter callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
int start = callAdapterFactories.indexOf(skipPast) + 1;
//遍历工厂类集合,返回符合要求的一个CallAdapter
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {//不等于null
return adapter;
}
}
}
很简单,只是简单的做了集合遍历的操作,然后返回符合标准的CallAdapter.
所以Retrofit的简单流程可以如下所示:
文章开头说过默认的CallAdapter返回的Call是ExecutorCallbackCall,那么这个Call对象是怎么生成的?在构建Retrofit的CallAdapter.Factory的时候,Retrofit.Builder有这么一段代码:
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor))
而platform对象的defaultCallAdapterFactory返回的就是ExecutorCallAdapterFactory:
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
//此处不为null
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
而ExecutorCallAdapterFactory工厂对象返回的CallAdapter对象如下:
public CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//Api方法的返回值必须是Call类型
if (getRawType(returnType) != Call.class) {
return null;
}
//获取Call的真实类型T
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?