枫叶「零碎记录」

Retrofit2框架解析

字数统计: 2.9k阅读时长: 12 min
2018/06/01 Share

什么是Retrofit框架?

Retrofit其实我们可以理解为OkHttp的加强版,它也是一个网络加载框架。底层是使用OKHttp封装的。准确来说,网络请求的工作本质上是OkHttp完成,而 Retrofit 仅负责网络请求接口的封装。它的一个特点是包含了特别多注解,方便简化你的代码量。并且还支持很多的开源库(著名例子:Retrofit + RxJava)。

本文中的Retrofit均指代Retrofit2.0,以目前最新的2.4.0版本为例子。

Retrofit入门

Retrofit 其实相当简单,简单到源码只有37个文件,其中22个文件是注解还都和HTTP有关,真正暴露给用户的类并不多。

Retrofit采用了建造者模式来保证这个类构建的确保了相应的默认值和规范性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static final class Builder {
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}

我们使用Retrofit2分以下三步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 第一步构建Retrofit
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://www.weather.com.cn/").build();
// 第二步添加服务接口
ApiService service = retrofit.create(ApiService.class);
// 第三步执行请求 利用Retrofit创建我们的接口对象,生成Call对象,并调用请求网络方法
service.weather().enqueue(new retrofit2.Callback<ResponseBody>() {
@Override
public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
try {
tvTest.setText(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(retrofit2.Call<ResponseBody> call, Throwable t) {
tvTest.setText(t.getMessage());
}
});

第一步解析构建Retrofit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public Retrofit build() {
//这里可以看出我们必需设置baseUrl
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//如果我们没有设置自定义的OkHttpClient,就用默认的OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//这个callbackExecutor用于回调到UI线程
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//将我们设置的Call适配器添加到列表中,比如RxJava的适配器
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//添加默认的Call适配器
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
//添加数据转换器,用于将网络请求返回的结果转换成我们需要的类型
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
//构建Retrofit
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}

从上面可以看到
(1)为什么说Retrofit2是基于OKhttp3的封装,因为CallFactory其实调用的就是OKhttpClient,所以说Retrofit2是基于OkHttp3的封装。

(2)callbackExecutor回调执行器,这个是用于网络请求返回后回调到主线程的。我们知道,在利用OkHttp3进行网络请求时,我们需要手动回调到主线程,以便更新UI。那我们来看看这个默认的defaultCallbackExecutor是不是这样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Platform {
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) {
}
return new Platform();
}
...
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);
}
}
}
}

从上面代码可以看到这个Platform的作用是判断当前作用的平台以及创建好主线程和进行回调。所以当我们调用platform的defaultCallbackExecutor时,实际上调用的是Android这个类的defaultCallbackExecutor方法,而这个方法返回的是MainThreadExecutor,它的作用就是利用handler将执行结果回调到主线程中。

(3)callAdapterFactories适配器列表,这里面存放的是所有的Call适配器CallAdapter。这个CallAdapter是干嘛的呢?我们知道Retrofit2底层是用Okhttp3来请求网络的,那势必是通过OkHttp3的Call来执行请求,但是我们在实际使用Retrofit2时,可能需要结合请他的三方库,常见的比如RxJava,那我们接口中所需要返回的可能就是Observable而不是Call了。

1
2
@GET("test/t")
Observable<WeatherBean> getObservableData();

所以Retrofit2就需要一个Call适配器CallAdapter,来将Call转换为我们需要的Observable,这就是CallAdapter的作用。

(4)converterFactories返回结果转换器列表,这里面存放的是将网络返回结果,也就是OkHttp3返回的Response,解析转换成我们需要的实际类型,比如WeatherBean实体类。如GsonConverterFactory就是一个常用的转换器,相当于Retrofit2把我们直接使用Okhttp3来请求网络数据时需要将返回结果进行Gson解析的动作也替我们做了。

第二步解析ApiService接口是如何转化为我们的接口请求调用的

在第二步骤中我们使用了retrofit.create添加服务接口

1
2
// 添加服务接口
ApiService service = retrofit.create(ApiService.class);

我们进一步看一下create方法到底做了什么事情看到以下代码其实做的事情明显,就是做了接口校验和创建动态代理。(不熟悉动态代理的童鞋可以去自行百度一下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public <T> T create(final Class<T> service) {
// 校验该类是不是接口以及校验该类必须不能继承自其他接口
Utils.validateServiceInterface(service);
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 {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//这里默认返回是false,所以不会执行
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args);
}
});
}

最后返回的是loadServiceMethod方法我们再进去看看调用了什么东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
// 加入锁进行解析
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 重点是这一步的解析
result = ServiceMethod.parseAnnotations(this, method);
// 会将已经解析过的方法缓存起来
serviceMethodCache.put(method, result);
}
}
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
abstract class ServiceMethod<T> {
// 这个抽象类似用来解析注解方法
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 这个工厂类似用来解析注解类比如Get、Post、Header等等之类的
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
// 获取方法的返回类型 我们可能是Call<T> 可能是Observable<T>
Type returnType = method.getGenericReturnType();
// 校验一下这个返回类型能否解析
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
// 将解析完的retrofit和请求参数在经历一次封装进行CallAdapter的适配并且做一些默认操作例如参数和回调的类型转换等等
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 根据注解解析并且创建CallAdapter对象
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
// 获取解析的对象类型
Type responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
// 校验规则
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
// 根据返回的类型去Convert的列表中对应并且创建相应的Converter的对象
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method) {
Type returnType = method.getGenericReturnType();
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create converter for %s", responseType);
}
}
private final RequestFactory requestFactory;
private final okhttp3.Call.Factory callFactory;
private final CallAdapter<ResponseT, ReturnT> callAdapter;
private final Converter<ResponseBody, ResponseT> responseConverter;
private HttpServiceMethod(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
CallAdapter<ResponseT, ReturnT> callAdapter,
Converter<ResponseBody, ResponseT> responseConverter) {
this.requestFactory = requestFactory;
this.callFactory = callFactory;
this.callAdapter = callAdapter;
this.responseConverter = responseConverter;
}
@Override ReturnT invoke(@Nullable Object[] args) {
// 所以最后一步调用的是这个函数转化为OkHttpCall类来进行请求
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}

(1)第一步是使用创建动态代理进一步进行解析方法和配置
(2)第二步解析完方法并且根据前面的Retrofit配置进一步的解析注解来配置CallAdapter对象和Converter对象
(3)第三步解析完所有的方法和对象后创建OkHttpCall对象来返回进行网络请求

第三步进入网络请求

在回顾一下上面我们请求的是这个实际上调用的就是OkHttpCall的queue方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
service.weather().enqueue(new retrofit2.Callback<ResponseBody>() {
@Override
public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
try {
tvTest.setText(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(retrofit2.Call<ResponseBody> call, Throwable t) {
tvTest.setText(t.getMessage());
}
});

由于我们在Retrofit2里的默认Android的CallAdapterFactory配置转换是ExecutorCallAdapterFactory(详情可以去看Platform类里)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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);
}
}
}

WX20180916-142652

然后我们来看以下OkHttpCall里的enqueue方法
WX20180916-143004

所以很明显里面实际上调用的就是Okhttp3的Call类来执行相应的网络请求。

总结

(1)这里我们分析了Retrofit的创建过程,可以发现Retrofit中核心部分包括OkHttpClient、Call适配器、Response转换器以及用于将请求回调到UI线程的回调执行器等。

(2)Retrofit的创建采用的是Builder模式,定制化程度很高,我们可以设置自己的OkHttpClient,也可以实现自定义的Call适配器和Response转换器,以及请求的回调执行器。

(3)可见Retrofit虽然做了很大程度的封装,但是灵活性扩展性依然很高,我们几乎可以扩展更改网络请求的大部分过程。

(4)Retrofit2中最主要的就是3个类:Retrofit、ServiceMethod和OkHttpCall。这三个类指责明确,相互配合共同完成整个网络调用的流程。

  • Retrofit负责供外部初始化和定制,保存CallAdapter的列表和ResponseConverterFactory列表。
  • ServiceMethod对应每一个接口方法的信息,包括解析注解和参数等,同时它也是连接Retrofit和OkHttpCall的桥梁。ServiceMethod中保存着当前接口对应方法所需要的CallAdapter和ResponseConverter。利用CallAdapter将OkHttpCall转换成接口需要的类型,供接口调用。利用toResponse方法让OkHttpCall调用ResponseConverter解析网络请求返回的结果。
  • OkHttpCall则是用来执行具体网络请求。Retrofit2没有直接使用OkHttp3的Call接口,而是有自己的Call接口。在OkHttpCall内部通过组合的方法持有OkHttp3的Call接口,并通过ServiceMethod的toCall方法得到OkHttp3的call来进行网络请求,减少对OkHttp3的耦合。
CATALOG
  1. 1. Retrofit入门
  2. 2. 第一步解析构建Retrofit
  3. 3. 第二步解析ApiService接口是如何转化为我们的接口请求调用的
  4. 4. 第三步进入网络请求
  5. 5. 总结