Retrofit2已经面世好久了,有不少好的文章分析过,这篇文章我只想记录本身阅读Retrofit 2.3.0源码后的分析过程,如何阅读源码以及分析我以为是最重要的。java
以前作过Gank的客户端,所以直接用Gank网站的请求了。git
构建retrofit对象:github
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://gank.io")
.build();
复制代码
定义请求interface, 能够把它内部的每个接口方法看作是一个封装了请求url及参数的方法,其返回值是可执行请求的对象,而在 Retrofit 中默认是 Call 可执行对象,也就是说 call 调用某个方法,如 enqueue 就能够异步执行请求。设计模式
public interface ApiService {
@GET("api/data/{type}/{size}/{page}")
Call<ResponseBody> getArticles(@Path("type") String type, @Path("size") int size,
@Path("page") int page);
}
复制代码
生成代理对象:api
ApiService apiService = retrofit.create(ApiService.class);
复制代码
获取 call 这个可执行请求的对象,并enqueue异步执行请求:缓存
Call<ResponseBody> call = apiService.getArticles("Android",10, 1);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
Log.d(TAG,response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
复制代码
call.enqueue会执行真正的请求,而且内部会切换到主线程回调到 onResponse 方法内可拿到最终结果。bash
附上 官方Retrofit使用文档数据结构
Retrofit本质上是对okhttp3的封装,其最大的优点就是解耦作的很是好,接下来就从源码角度分析下。异步
构建Retrofit用到了 Builder 模式,很适合自定义一些东西。先走到 baseUrl 方法内看下:ide
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null)
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
复制代码
将字符串类型的url解析成 HttpUrl对象,这个对象能够理解为拆分了url的协议、域名、端口、路径等变量并保存在了一个对象中,须要哪一个部分就能够随时拿出,最后保存下 httpUrl 变量。
最简单的就是设置一个地址,而后直接调用 build 方法:
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
复制代码
若是不在构建Retrofit时设置 client 那么就会默认建立一个 OkHttpClient, 前面已经说过 Retrofit 是对 okhttp 的封装而已,本质上仍是okhttp 进行请求,而如今只是分析 Retrofit, 所以不打算深刻OkHttpClient, 可是根据它的接口类型也能判断是一个 生产okhttp中的Call对象的工厂, 而Call对象就是可执行任务的对象, Retrofit 中也有 Call 致使有点混乱。。须要好好辨别下。
若不设置 callbackExecutor 也会经过 platform.defaultCallbackExecutor() 建立一个默认的,经过看源码发现Retrofit也就支持两个平台,一个是Java8,一个就是Android :
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor
callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
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);
}
}
}
复制代码
它会返回一个 MainThreadExecutor 对象,而它的实现很是简单,就是经过Handler将线程切换到主线程,记住这个 callbackExecutor , 它会在某个地方执行 execute 方法这个时候会切到主线程进行回调。
adapterFactories列表对象能够把它理解为 生产 adapter 的工厂,而 adapter 从名字上来看是适配器,它调用其中的 adapt 方法返回的就是可执行对象!在 Retrofit 里默认的实现就是 Call 对象,而且因为 Retrofit 的神奇解耦,它能够自定义任何CallAdapter 和 Factory,最有名的就是RxJava,其返回的可执行对象变成了Observable而已 ,列表表示能够添加多个 callAdapter工厂, 根据你写的接口方法的返回值判断选择哪一个适配器。
默认状况下调用 platform.defaultCallbackExecutor() 建立 ExecutorCallAdapterFactory ,这个类很关键,工厂顾名思义就是生产CallAdapter的,其中的 get 方法返回了一个 CallAdapter 对象,这个对象会在某个关键时刻调用 adapt 从而返回 Call 对象,这个调用流程以后再详解。
converterFactories 转换器工厂,其套路和 adapterFactories 很是相似,它的做用就是将请求后返回的数据转换成你想要的数据结构,应用最广的应该是 GsonConverterFactory , 能够将结果用 Gson 转换成自定义好的数据结构。其默认实现是 BuiltInConverters ,这个默认的工厂返回的 Converter 基本没作什么事情,基本只是把 okhttp 返回给 Retrofit 的 ResponseBody 数据结构返回出去。所以暂时不须要太过在乎。
最后以这些对象做为参数传给 Retrofit 构造一个 Retrofit 实例。总结下关键的几个对象:将 url 解析成 HttpUrl 对象并保存供之后使用;在不自定义的状况下默认建立 callFactory, 这个 OkHttpClient 的实例,最终会经过这个工厂生成 okhttp 中的 call 对象来执行真正的请求;callbackExecutor默认实现是 MainThreadExecutor 是用来最后切换到主线程用的;adapterFactories用来生产adapter,默认是 ExecutorCallAdapterFactory,最后会返回 Call 对象;converterFactories默认实现是 BuiltInConverters, 基本上就是将 okhttp 返回的 ResponseBody 返回出去。
动态代理这个能够说是 Retrofit 最精华的地方了。再此以前须要理解反射和动态代理,推荐两篇不错的文章:反射、动态代理。
构建完 Retrofit 对象后,须要调用 retrofit.create(ApiService.class), 生成 ApiService 接口对应的动态代理对象。
public <T> T create(final Class<T> service) {
// ......
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
// 获取目前的平台,对于咱们来讲就是Android平台
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// ......
// 构建 接口方法 对象,此对象主要是解析注解并拼接成请求所需的参数。
// 它是最后用来给okhttp使用并真正发送请求。
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
// 本质上就是Retrofit对Okhttp的Call对象进一步的封装
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 最后默认返回的也是一个Call可执行任务对象(固然RxJava返回的对象就不是默认的了),
// 其实相似因而OkHttpCall的代理类,只不过内部加了切换到主线程的操做。
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
复制代码
部分没啥用的代码省略了,剩下的都是关键代码,而且加了注释。这里再说下动态代理相关的,create 方法返回值是第一部分的使用步骤中的 apiService, 它是动态代理生成的对象。调用动态代理对象的方法后会调到 invoke 方法,返回值对应使用步骤中的 call 对象。
进入 loadServiceMethod 方法,能够看到对 serviceMethod 会有一个缓存,一个方法只会解析一次,以后重复利用。而后经过 build 构建一个 ServiceMethod 对象。
public ServiceMethod build() {
// 跟进 createCallAdapter 能够看到它返回的 CallAdapter 是根据方法的返回类型,
// 如本文使用步骤中返回类型是 Call,那么就会返回以前已建立过的默认 CallAdapter
callAdapter = createCallAdapter();
// 返回结果类型,对于 Retrofit 默认返回结果类型是 ResponseBody,
// 所以在阅读源码时直接把 responseType 看作 ResponseBody 类型。
responseType = callAdapter.responseType();
// ......
// 跟进 createResponseConverter 方法能够看到它是根据 responseType 返回对应的 Converter。
responseConverter = createResponseConverter();
// 遍历解析方法上的注解如 @GET、@POST等(拆分注解中的字符串,将参数名记录)
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// ......
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
// ......
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
// ......
// 遍历解析形参的注解,如@Path、@Query等.
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
// ......
return new ServiceMethod<>(this);
}
复制代码
其实 ServiceMethod 不是理解 Retrofit 的关键,只需知道它封装了解析注解逻辑和记录参数。
直接看下 OkhttpCall 的enqueue方法
@Override public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
synchronized (this) {
// ......
// 这里的 call 就是 OkHttp 的 call
call = rawCall = createRawCall();
}
// ......
// okhttp 的 call 异步执行并回调,注意这里依然在异步线程中。
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawRespon
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
// ....
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
复制代码
最后一步经过 callAdapter.adapt(okHttpCall) 返回一个最终可执行对象,这里咱们都是看默认的,所以 callAdapter 是 ExecutorCallAdapterFactrory 中 get 获取的 callAdapter, 其 adapter 方法返回的是 ExecutorCallbackCall 也是实现了 Call 接口,以前说过此对象是 okHttpCall 的代理对象,所以传入 okHttpCall 实例,而内部干的最关键的一件事就是在异步执行请求完成后经过 callBackExecutor(以前早已准备好的Handler切换) 切换到主线程。
绿色线框表明咱们使用 Retrofit 须要作的几步。
Retrofit 内部有大量的设计模式,设计的很是巧妙,多看源码也能提升咱们的代码设计能力。build 阶段用了构造者模式,create 用了动态代理模式,CallAdapterFactory 和 ConverterFactory 用了适配器模式,等等。
为了加深对Retrofit的理解以及体会它的好用程度,写了一个自定义ConverterFactory。
public final class StringConverterFactory extends Converter.Factory {
private final static String TAG = "StringConverterFactory";
@Nullable
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
if(type == String.class){
return StringResponseConverter.INSTANCE;
}
return null;
}
@Nullable
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if(type == RequestBody.class){
return StringRequestBodyConverter.INSTANCE;
}
return null;
}
final static class StringResponseConverter implements Converter<ResponseBody, String> {
final static StringResponseConverter INSTANCE = new StringResponseConverter();
@Override
public String convert(ResponseBody value) throws IOException {
Log.d(TAG, value.toString());
return value.string();
}
}
final static class StringRequestBodyConverter implements Converter<RequestBody, RequestBody> {
final static StringRequestBodyConverter INSTANCE = new StringRequestBodyConverter();
@Override
public RequestBody convert(RequestBody value) throws IOException {
Log.d(TAG, "no change, hahaha...");
return value;
}
}
}
复制代码
支持String的泛型参数,其实内部也就是把 ResponseBody 提早转成 String 并打印而已。在使用的时候须要在构建 Retrofit 时添加:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://gank.io")
.addConverterFactory(new StringConverterFactory())
.build();
复制代码
最后对 Retrofit 作一个总结 。Retrofit 是对 okhttp3 的封装,其最大的特性就是解耦,你能够自定义不少你想要的东西,最知名的就是 RxJava 的配合使用。
首先调用 build 方法建立生产 okhttp3 的 call 对象的callFactory、建立用来切换线程的 callBackExecutor、建立生产 CallAdapter 的 CallAdapterFactory、建立生产 Converter 的 ConverterFactory。
接着调用 retrofit.create 建立动态代理对象,调用接口方法会触发 invoke 方法,invoke 内建立 ServiceMethod并作了注解解析、建立OkhttpCall(对okhttp3的call进一步封装),最后经过 CallAdapter.adapt 方法返回可执行对象默认是 ExecutorCallBackCall。
最后调用 call.enqueue 后 okhttp3将请求 ServiceMethod 解析好的url和参数,最终返回结果会被 Converter.convert 解析成你想要的数据模型(默认是ResponseBody),最后经过 callBackExecutor.execute 切换到主线程将数据回调给开发者。
ps:作完 Retrofit 源码分析后,还想看下 RxJava 的源码,为了更深刻理解 RxJava 和 Retrofit 共同使用的原理。最近想到一句话感受蛮有意思的:当你不知道作什么的时候,去看看源码或官方文档吧。