前言
这篇文章我将从Retrofit的基本用法出发,透过其使用步骤,一步步的探究Retrofit的实现原理及其源码的设计模式。这篇文章可能会将Retrofit中用到的设计模式和其实现原理穿插着写,所以各位同学也可以选择性的阅读。而对于Retrofit具体使用还不太清楚的同学可以去看的另一篇文章Retrofit2的使用介绍
Retrofit基本用法
我以用户登录作为示例:
声明接口
首先我们先定义一个登录服务接口LoginService
,如下:
public interface LoginService {
@FormUrlEncoded
@POST("login")
Call<String> login(@Field("username") String name, @Field("password") String password);
}
创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://ittiger.cn")
.addConverterFactory(GsonConverterFactory.create())
.build();
发起请求
LoginService service = retrofit.create(LoginService.class);
Call<User> call = service.login("user", "pwd");
call.execute()或call.enqueue()
Retrofit关键类
在讲Retrofit实现原理之前,我先说下Retrofit里面涉及到几个关键类都是干什么用的
Retorift:
负责配置请求过程中的基本参数,如:请求地址,结果转换器,自定义OKHttpClient等,同时还会生成请求接口对象Call:
网络请求执行者(Retrofit.Call
),比如:上面示例中最后调用login
方法得到的Call
对象就是此接口的实例OkHttpCall:
此类是Retrofit.Call
接口的实现,示例中最后调用login
方法得到的Call
对象就是此类的实例。但是其底层网络请求执行都是通过OkHttp.Call
接口间接执行的,也就是说OkHttpCall
是对OkHttp.Call
网络请求功能的封装。Converter & Converter.Factory:
分别负责网络请求结果转换以及生成Converter
转换器CallAdapter & CallAdapter.Factory:
分别负责对Retrofit.Call实例(OkHttpCall)
进行适配及生成CallAdapter
适配器Platform:
确定Retrofit
当前运行平台,以及确定当前平台默认的的CallAdapter.Factory
和Executor
ExecutorCallAdapterFactory:
Android平台下的默认CallAdapter.Factory
实现ServiceMethod:
解析接口服务所有注解、生成请求对象Request
、解析请求结果Response
ParameterHandler:
服务接口方法(login()
)参数解析处理器,配合ServiceMethod
进行服务接口参数注解解析RequestBuilder:
根据参数和URL
构造请求需要的OkHttp.Request
对象
以上就是Retrofit源码实现中比较关键的10个类及其相关作用
> 实现 >> 设计模式” target=”_blank”>使用流程 >> 实现 >> 设计模式
Builder模式创建Retrofit
Retrofit场景
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://ittiger.cn")
.addConverterFactory(GsonConverterFactory.create())
.build();
上面代码的对象创建方式看着是不是似曾相识,看着很眼熟,没错,Android里面的Dialog的创建就是使用的这种方式:Builder模式
Builder模式定义
将一个复杂对象的构建与它的表示分离,使得同样的构建可以创建不同的表示
Builder模式使用场景
- 相同的方法不同的执行顺序产生不同的结果
- 多个部件都可以装配到一个对象中,但是产生的结果不同
Builder模式类图
Retrofit中的Builder模式
Retrofit
中的Builder模式
是简化版的Builder模式
,省略了抽象建造者和指挥者- 不同的配置会对
Retrofit
产生不同的影响,如果通过addCallAdapterFactory()
配置CallAdapterFactory
和不配置CallAdapterFactory
会对Retrofit
产生完全不同的影响。 - 如果
Retrofit
中使用构造方法的方式创建对象,则需要实现多个不同参数的构造方法,而使用构造方法创建对象时如果参数太多,很多时候参数代表的意思是不太理解的,总归来说就是创建过程不直观。
Builder模式优缺点
- 优点:
- 不需要知道产品内部的组成细节,产品与创建过程解耦
- 分步组装产品,使得产品的创建过程更精细更清晰
- 容易扩展,新产品只需要新建一个建造者即可
- 缺点:
- Builder模式创建的产品差异性小,使用范围受限制
- 不同的产品会产生多个建造者和指挥者
> Platform” target=”_blank”>Retrofit创建流程 >> Platform
在创建Retrofit过程中有这样一行代码:
Retrofit retrofit = new Retrofit.Builder()
...
.build();
从代码可以看到在创建Retrofit
时得先根据Retrofit.Builder
内部类的默认构造方法Retrofit.Builder()
创建一个Builder
对象,所以我们来看看这个默认构造方法里都做了些什么事:
public Builder() {
this(Platform.get());
}
OK,我们再来看看我们前面说到的Platform
这个平台类的静态方法get()
//静态实例对象,类加载就确定了
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
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) {
}
try {
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
...
}
通过上面的代码我们可以很明确的知道,在Platform
类加载的时候它就通过反射的机制确定了当前运行的平台是属于哪一个,是Android
,是Java8
还是IOS
,并生成对应的平台类的实例,get()
方法是用来获取当前的平台类的实例。
目前,我们只关注Android
平台下的Platform
实例,我们也来看看Android
平台类中做了些什么:
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
可以看到Android
类中重写了Platform
类的两个方法defaultCallbackExecutor()
和defaultCallAdapterFactory(Executor callbackExecutor)
- 前者就是用来返回当前平台下默认的
Executor
,这Android
平台下就是MainThreadExecutor
这个类的实例,可以看到这个执行器主要就是用来进行线程切换的,因为我们知道安卓平台下所有的UI操作都必须在UI线程中执行。 - 后者就是用来返回当前平台下默认的
CallAdapter.Factory
- 当然你也可以不使用这两个默认值,都可以在创建
Retrofit
过程中自定义配置自己需要的相关实例
> ExecutorCallAdapterFactory” target=”_blank”>Retrofit创建流程 >> ExecutorCallAdapterFactory
看完Platform
之后紧接着我们再来看看Android
平台下默认的CallAdapter.Factory
实现ExecutorCallAdapterFactory
都做了些什么,这里只贴关键代码:
public interface CallAdapter<T> {
abstract class Factory {
public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
...
}
}
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;//对应默认的MainThreadExecutor
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
...
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
...
}
大家看源码可以发现CallAdapter.Factory
工厂是通过get()
方法来创建CallAdapter
的,所以ExecutorCallAdapterFactory
关键代码也是在get()
方法的实现上,上面的代码中我们可以看到get()
方法返回一个CallAdapter
实例,这就是我前面介绍关键类作用时说到的CallAdapter.Factory
主要负责生成CallAdapter
的实现。
该类中,我们从其类的命名以及代码实现结构上来看,ExecutorCallAdapterFactory
其实也使用了一种设计模式,那就是工厂方法模式
,其实Retrofit
中还有一个地方也使用了工厂方法模式
,那就是Converter & Converter.Factory
它的实现方式和CallAdapter & CallAdapter.Factory
是一样样的。
工厂方式模式(创建CallAdapter & Converter)
本文我就已CallAdapter
进行举例,看懂CallAdapter
的创建原理之后,再看Converter
的创建也就比较简单,都是一样的道理。
Retrofit场景
Retrofit
中使用工厂方式模式的场景我在前面讲ExecutorCallAdapterFactory
实现的时候已经讲过了,这里就不重复举例了,大家可以对照着源码看下。
工厂方法模式定义
一个用于创建对象的接口,让子类决定实例化哪个类
工厂方法模式使用场景
- 不需要知道其具体的类名,只需要知道生成它的工厂
- 一个类通过其子类来决定创建哪个对象
工厂方法模式类图
Retrofit中的工厂方法
Retrofit
中使用工厂方法模式可以讲CallAdapter
的创建与具体实现充分解耦,对于创建我们只需要知道其工厂即可,不需要关注是如何实现- 所以我们可以通过
addCallAdapterFactory()
和addConverterFactory()
很方便的自定义我们自己所需要的适配器工厂和数据转换工厂 - 通过
addCallAdapterFactory()
可以很方便的让Retrofit
支持RxJava
特性,而通过addConverterFactory()
可以自定义配置们想要的转换器,让我们可以将请求数据结果转换成我们想要的任意类型。
这些就是Retrofit
使用工厂方法模式带来的好处。
工厂方法模式优缺点
- 优点
- 只关注产品工厂即可,不需要关注产品如何创建,由工厂确定如何创建
- 扩展性好,新增产品时,只需要新增一个具体工厂和具体产品
- 缺点
- 新增产品时,需要新增具体工厂和具体产品类,使系统变得庞大
- 系统中加入抽象层,增加了系统的抽象性和理解难度
> CallAdapter” target=”_blank”>适配器模式 >> CallAdapter
Retrofit场景
先来看看CallAdapter
在Retrofit
中的使用场景
public interface CallAdapter<T> {
public Type responseType();
public <R> Call<R> adapt(Call<R> call);
}
//ExecutorCallAdapterFactory中生成CallAdapter实例
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
前面讲到ExecutorCallAdapterFactory
会生成一个CallAdapter
实例。而CallAdapter
这个名字看着是不是也很眼熟,也有种似曾相识的感觉,没错,CallAdapter
与我们在Android
中使用ListView
或RecyclerView
时经常用到的各种Adapter
一样也是一个适配器。
那CallAdapter
是来适配什么的呢?
还记得前面介绍关键类的时候说到的OkHttpCall
吗?CallAdapter
就是来适配OkHttpCall
实例的,结合上面的代码来说的话在调用CallAdapter.adapt
方法时OkHttpCall
实例会作为参数传递给adapt
方法从而交给CallAdapter
去进行适配。
在我前面举的登录示例中,我们调用login()
方法得到的Call
实例就是CallAdapter
适配OkHttpCall
之后得到的一个新Call
实例对象,至于为什么是这样,我后面会一一讲解,各位看官不要离开
所以Retrofit
在这个地方又使用了一种设计模式:适配器模式
适配器模式定义
将一个类的接口变成客户端所需要的另一个接口,从而使原本因接口不匹配而无法一起工作的两个类可以在一起工作
适配器模式使用场景
- 需要复用现有类,而现有类不符合系统需求
- 需要一个统一的输出接口,而输入端类型不可预知
适配器模式类图
Retrofit中的适配器模式
//ExecutorCallAdapterFactory中生成CallAdapter实例
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
Android
平台下默认的CallAdapter
会将OkHttpCall
和 MainThreadExecutor
两个实例对象适配成一个新的Call
实例,这个新的Call
实例在执行过程中就具备了切换到UI线程的功能。
那Retrofit
在这个地方为什么要使用适配器模式将OkHttpCall
进行适配了,直接拿过来用不就可以了吗?
前面讲过OkHttpCall
仅仅只是对OkHttp.Call
执行网络请求操作的封装,没有其他功能,也就是说OkHttpCall
也只有网络请求的功能,而Retrofit
是支持多个平台的(安卓,Java8,IOS,甚至包括支持RxJava特性),而不同的平台可能具有不同的特性。
如果在请求过程中需要用到这些特性的话,那么单靠OkHttp.Call
是无法完成的,而如果在其他地方柔和进这些特性的支持可能就会使得框架结构不那么严谨平台解耦性比较差,甚至有可能会增加更多的接口。
Retrofit
通过使用适配器模式将平台特性与OkHttpCall
适配成一个最终我们需要的Call
实例,这样的话我们在使用过程中只需要关注最后拿到的Call
对象,而不需要关注底层这个Call
实例到底是什么样的,这也就为我们支持更多的特性提供了可能。比如对RxJava特性的支持,我们只需要提供一个支持RxJava
特性的CallAdapter
适配器即可,所以我们就可以通过addCallAdapterFactory()
配置我们提供的支持RxJava
特性的CallAdapter.Factory
适配器模式优缺点
- 优点
- 复用性好,引入适配器类来重用适配者类,无需修改原有代码
- 增加类的透明性,将适配过程封装在适配器类中,对使用者来说相对透明
- 灵活性扩展性好,通过配置可以随时更换适配器
- 缺点
- 使用适配器会使系统整体不好把握,调的是A接口,却被适配成了B接口的实现
> ExecutorCallbackCall” target=”_blank”>静态代理模式 >> ExecutorCallbackCall
Retrofit场景
还是先来看看Retrofit
中使用ExecutorCallbackCall
的场景
//ExecutorCallAdapterFactory中生成CallAdapter实例
return new CallAdapter<Call<?>>() {
...
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
在上面CallAdapter
实现中,可以发现它将OkHttpCall
适配成了一个新的Call
实例:ExecutorCallbackCall
,所以我们接着看看ExecutorCallbackCall
的具体实现代码
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;//Android平台下的Executor:MainThreadExecutor
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) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
//Android平台下此处进行了线程切换
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
//Android平台下此处进行了线程切换
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
}
可以看到我们通过login()
方法拿到Call
实例(也就是ExecutorCallbackCall
)之后,在执行网络请求时,在ExecutorCallbackCall
的实现中其实都是将具体操作委托给OkHttpCall
在执行。所以Retrofit
在ExecutorCallbackCall
中又使用了一种设计模式:静态代理模式
静态代理模式定义
为其他对象提供一种代理以控制对这个对象的访问
静态代理模式使用场景
无法访问或不想直接访问某个对象
静态代理模式类图
Retrofit中的静态代理
Retrofit
中使用ExecutorCallbackCall
代理OkHttpCall
具体请求操作,可以将Call
的使用与底层实现进行解耦,不用关心底层具体请求接口的实现,所以如果将来出现了一个比OkHttp
更好的网络请求库,我们完全可以将OkHttp
替换掉,即便这样也不会影响外部API接口在项目中的使用。
静态代理的优缺点
- 优点
- 协调调用者与被调用者,降低系统耦合度
- 减小外部接口与内部接口实现的关联,降低耦合
- 缺点
- 委托对象与代理对象需要实现相同的接口,当接口类增加方法时,除了所有实现类需要增加该方法外,所有代理类也需要实现此方法,增加了维护难度
- 一个代理类只能代理一种类型的对象
> Retrofit.create()” target=”_blank”>动态代理 >> Retrofit.create()
先看下Retrofit.create()
方法的具体实现代码:
public <T> T create(final Class<T> 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, Object... args)
throws Throwable {
...
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
相信很多人在刚开始用Retrofit
时都会有一点疑问,我们明明声明的是接口,为什么通过create()
方法就能创建出一个对象实例呢?
通过上面的实现源码我们找到了答案,那就是使用了JDK中提供的动态代理机制,它会在运行过程中为我们声明的服务接口动态的创建出一个代理对象,以便实现我们的请求操作。我个人认为这是Retrofit
框架得以实现的一个核心之处,另外一个核心之处就是其完善的注解机制,关于其注解本文就不说,主要就是一些注解的声明和解析,比较简单,感兴趣的可以去看看。
上面的源码中我们可以看到,运行过程中得到服务接口的代理对象之后,当我们调用login()
这样的接口方法时,其实真实执行的是上面源码中写的invoke()
方法,所以我们调用login()
方法时其实是执行了如下三步:
- 根据反射得到接口方法
Method
对象生成对应的ServiceMethod
对象,该对象会对该声明方法上的所有方法注解、参数注解进行解析以得到一个请求所需要的所有信息 - 得到
ServiceMethod
对象之后,会根据该对象和方法调用时传递的参数生成OkHttpCall
对象,也就是具体的网络实施者 - 将
OkHttpCall
作为CallAdapter
适配器中adapt()
方法的参数传递给CallAdapter
进行适配,最后得到我们所需要的ExecutorCallbackCall
对象,也就是调用login()
方法得到的Call
实例对象
动态代理使用场景
静态代理特点一个代理对应一种类型,如果有多个类需要代理则需要多个代理,而且维护成本高,而动态代理就是来解决此类问题
动态代理特点
运行期由JVM通过反射机制动态生成,可以代理多种类型,代码复用性高。但是只能代理Java接口,不能代理Java实现类。
Call.enqueue() & Call.execute()实现
前面从Retrofit
的配置、创建、调用接口方法得到Call
实例,基本用法都已经讲的差不多了,现在我们来看基本用法的最后一步Call.enqueue() & Call.execute()
前面讲过调用接口方法比如login()
时,Android
平台下默认得到的是ExecutorCallbackCall
实例,而ExecutorCallbackCall
实例中执行网络请求的实际上又是OkHttpCall
,所以我们来看OkHttpCall
中的Call.enqueue() & Call.execute()
两个方法的实现,我以Call.enqueue()
为例,另外一个大家可以自己去看看
下面是该方法实现的关键代码:
OkHttpCall.enqueue()
@Override public void enqueue(final Callback<T> callback) {
...
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
//如果okhttp3.Call为空,则先创建该实例
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
...
//又讲网络执行转交给okhttp3.Call实例来执行
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
//将okhttp3.Response结果包装成Retrofit中的结果对象Response
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
...
}
private void callFailure(Throwable e) {
...
}
private void callSuccess(Response<T> response) {
...
}
});
}
前面介绍关键类时说过OkHttpCall
底层网络执行其实是OkHttp.Call
在执行,从上面的代码我们就可以看出来(代码关键地方我加了注释),上面代码关键第一步是先创建一个okhttp3.call
实例,所以我们同样看看创建okhttp3.call
实例的代码是怎么实现的
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
...
return call;
}
通过上面的createRawCall()
方法实现我们可以发现,它会首先通过ServiceMethod.toRequest()
方法生成一个OkHttp.Request
对象(这部分代码比较简单,我就不细说了),然后根据ServiceMethod
中的成员变量CallFactory
创建一个okhttp3.Call
实例。但是这个CallFactory
是怎么来的呢?其实我们可以猜到这个CallFactory
实例就是OkHttpClient
实例。但是我们还是看看ServiceMethod
的创建过程
ServiceMethod创建
//在Retrofit.create()方法实现的第一步就是通过loadServiceMethod()方法创建ServiceMethod,这是其实现
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
//下面是ServiceMethod相关关键代码
final class ServiceMethod<T> {
final okhttp3.Call.Factory callFactory;
ServiceMethod(Builder<T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
...
}
static final class Builder {
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
...
}
public ServiceMethod build() {
//创建CallAdapter
callAdapter = createCallAdapter();
//得到请求结果返回类型,接口方法声明
responseType = callAdapter.responseType();
...
//创建得到Converter结果转换器
responseConverter = createResponseConverter();
...
return new ServiceMethod<>(this);
}
}
}
通过上面的ServiceMethod
创建过程的相关代码可以看出,ServiceMethod
中的实例变量callFactory
其实是调用Retrofit.callFactory()
方法所得,大家也可以看看上面我注释的CallAdapter
和Converter
的创建过程,所以我们再来看看这个方法的实现
public okhttp3.Call.Factory callFactory() {
return callFactory;
}
可以看到该方法只是返回了Retrofit
中的callFactory
实例,同样,我们再来看看Retrofit
中的callFactory
实例是怎么来的
public final class Retrofit {
private final okhttp3.Call.Factory callFactory;
...
Retrofit(okhttp3.Call.Factory callFactory, ...) {
this.callFactory = callFactory;
...
}
public static final class Builder {
private okhttp3.Call.Factory callFactory;
...
public Builder client(OkHttpClient client) {
return callFactory(checkNotNull(client, "client == null"));
}
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = checkNotNull(factory, "factory == null");
return this;
}
public Retrofit build() {
...
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
...
return new Retrofit(callFactory, ...);
}
}
}
通过上面的代码,我们可以看出Retrofit
中的callFactory
实例就是我们使用的OkHttpClient
实例,所以这就验证了我们前面猜测的serviceMethod.callFactory
就是OkHttpClient
实例的猜想。
Ok,回到我们前面将的OkHttpCall.equeue()
方法的实现流程上来。
请求结果解析
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
//将okhttp3.Response结果包装成Retrofit中的结果对象Response
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
...
}
创建完okhttp3.call
实例之后,调用该实现的equeue()
方法开始执行网络请求,请求执行完成之后,会调用parseResponse
方法,我们来看看这个方法实现的关键代码:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
...
//上面省略的这段代码是对请求失败时的结果处理,大家可以自行查看源码
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
这个方法中,当请求成功时,会调用serviceMethod.toResponse()
这个方法,我们来看看这个方法又做了哪些事情:
T toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
很明显,上面方法中就直接调用了ServiceMethod
中的Converter
实例进行结果转换,也就是说在这个地方Retrofit
会帮我们把网络请求结果转换成我们所需要的类型,转换成功之后会调用Response.success(body, rawResponse)
将转换后的结果包装成Retrofit
中的Response
对象。
获取配置的Converter
问题又来了,上面的Converter
是怎么来的呢?
在前面给出的ServiceMethod
创建过程的代码块中,我对ServiceMethod
中创建Converter
实例的代码进行了注释,我们再回过头来看看这段代码:
//ServiceMethod.Buibler中的方法
private Converter<ResponseBody, T> createResponseConverter() {
...
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
//Retrofit中的方法
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations) {
...
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
return (Converter<ResponseBody, T>) converter;
}
}
...
throw new IllegalArgumentException(builder.toString());
}
通过上面的代码我们可以看到会从Retrofit
的converterFactories
转换器工厂集合中去查找当前接口方法对应的转换器工厂。其实这也告诉我们可以在创建Retrofit
时配置多个Converter.Factory
转换器工厂,也就是说我们一个接口服务中如果声明的多个接口方法的返回值不一样时,我们可以针对性的配置多个不一样的结果转换器工厂去进行结果解析,而不用为了保持结果类型一致对接口进行其他处理。
上面创建ServiceMethod
时得到CallAdapter
的过程与得到Converter
的过程基本一样,我就不赘述了。
到这里,Retrofit
的实现原理、实现流程以及其源码实现过程中用到的设计模式就介绍完了。
内容好长,时间好长~~~~
原创文章,本文采用知识共享署名 2.5(中国大陆许可协议)进行许可,欢迎转载,但转载请注明来自ittiger.cn,并保证转载后文章内容的完整性。本人(laohu)保留所有版权相关权利。