Fork me on GitHub

Retrofit2(1)

用途

Retrofit is the class through which your API interfaces are turned into callable objects.

译:Retrofit通过设置的API接口转换为可以被调用的类。

所以,这样我们就可以知道Retrofit是一个HTTP框架,那么在没有Retrofit之前,我们是如何请求的。

  1. build Request参数
  2. 因为网络请求是一个耗时操作,Android不允许在主线程中进行,所以需要线程或利用Excutor创建新线程
  3. 异步后,通过运行非主线程来进行网络请求
  4. 请求成功,获取到服务器返回的数据之后,callback回调给应用上层
  5. 进行切换线程,数据处理等等

发展历程

  1. 手写上述过程
  2. 官方出了AsyncTask
  3. 第三方库Volly…

优缺点、对比什么的就先挖个坑

Retrofit

接下来我们来看看Retrofit有什么能力取代其他框架的。

举个栗子

1
2
3
4
5
6
7
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl("http://news-at.zhihu.com/")
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(rxJavaCallAdapterFactory)
.build();
zhiHuApi = retrofit.create(ZhiHuApi.class);
1
2
3
4
5
6
7
8
public interface ZhiHuApi {

@GET("api/4/news/latest")
Observable<ZhiHu> getStoriesInfo();

@GET("api/4/news/before/{date}")
Observable<ZhiHu> getOldStoriesInfo(@Path("date") String date);
}

分析流程

前面叙述了没有 Retrofit 是如何进行网络请求的,那我们按照给出步骤来看看Retrofit是如何实现的。

  1. build request(API参数配置)
  2. executor
  3. 解析数据,返回T(需要的数据类型,下同)给上层

Retrofit的版本

  1. 通过注解配置API参数
  2. CallAdapter(理解为 executor)
  3. Converter(解析数据并转换为T)

创建Retrofit 对象

1
2
3
4
5
6
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl("http://news-at.zhihu.com/")
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(rxJavaCallAdapterFactory)
.build();

定义API

1
2
3
4
5
6
7
8
public interface ZhiHuApi {

@GET("api/4/news/latest")
Observable<ZhiHu> getStoriesInfo();

@GET("api/4/news/before/{date}")
Observable<ZhiHu> getOldStoriesInfo(@Path("date") String date);
}

这里使用到注解@GET@PATH

获取API实例

1
ZhiHuApi zhiHuApi = retrofit.create(ZhiHuApi.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
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

动态代理?(不懂,逃…)

动态生成接口的实现类(动态),并创建它的实例(代理)。代理把对接口的调用转发给InvocationHandler实例,在 InvocationHandler 的实现中,执行真正的逻辑。

没错,下面就是 InvocationHandler 的源码啦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});

为什么要用动态代理?因为对接口的所有方法的调用都会集中转发到 InvocationHandler 的 invoke 函数中,我们可以集中进行处理,更方便了。

调用 API 方法

这里的代码和RxJava结合了

1
2
3
4
5
6
7
8
9
10
11
12
Network.getZhiHuApi()
.getStoriesInfo()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ZhiHu>() {
@Override
public void accept(ZhiHu zhiHu) {
mSwipeRefreshLayout.setRefreshing(false);
mStoriesBeanList = zhiHu.getStories();
mZhiHuAdapter.setData(mStoriesBeanList);
}
});

在这里完成了HTTP请求,并将数据转化为需要的类型了。所以这里的很很很重要的地方。

那么是如何进行请求和转换的呢?

进行HTTP请求&数据转换(重要)

1
2
3
4
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

这几行代码完成了ServiceMethodbuild OkHttpCallCallAdapter adapt

ServiceMethod< R,T>

/* Adapts an invocation of an interface method into an HTTP call. /

ServiceMethod 作用在上面已经给出,翻译过来就是将接口方法转化为HTTP调用

一个 ServiceMethod 对应着一个API接口方法,第一行中的 loadServiceMethod 方法的作用是用于加载 ServiceMethod

1
2
3
4
5
6
7
8
9
10
11
12
13
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();
serviceMethodCache.put(method, result);
}
}
return result;
}

在 loadServiceMethod 中你会发现它实现了缓存机制,同一个 Api 的同一个方法,只会被创建一次。

ServiceMethod 的构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ServiceMethod(Builder<R, T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}

成员变量:callFactory 、callAdapter 、responseConverter 、parameterHandlers

  • callFactory 负责创建 HTTP 请求,HTTP 请求被抽象为 okhttp3.call 类,表示随时可以执行 HTTP请求
  • callAdapter 将 retrofit2.Call< T> 转为 T (retrofit2.Call 表示对一个 Retrofit 方法的调用),这一个过程会执行一个 HTTP 请求,服务器返回数据(OkHttp3.call实现),并且把数据转换为声明的 T 类型对象(Converter<?, String> 实现)
  • responseConverter (Converter 类型) 负责将服务器返回的数据转化为 T 类型的对象
  • parameterHandlers 负责解析API 定义时候每个方法的参数,并且在构造HTTP请求的时候设置参数
callFactory
1
this.callFactory = builder.retrofit.callFactory();

我们在构建 retrofit 的时候就会指定一个 callFactory ,如果不指定,系统会默认设置一个 okhttp3.OkHttpClient

1
2
3
4
5
6
7
/**
* The factory used to create {@linkplain okhttp3.Call OkHttp calls} for sending a HTTP requests.
* Typically an instance of {@link OkHttpClient}.
*/
public okhttp3.Call.Factory callFactory() {
return callFactory;
}
callAdapter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}

先进行一些检查,然后 return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations); 由 retrofit 提供。

在 Retrofit 类内部,遍历CallAdapter.Factory 列表,由工厂提供,如果工厂没有提供需要的 callAdapter 就抛异常。

我们可以在构建 retrofit 时指定 callAdapter。

responseConverter
1
2
3
4
5
6
7
8
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
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);
}
}

responseConverter 由 retrofit 提供,看代码可以知道原理和 callAdapter 一致,先看工厂里面有没有,没有就报异常,同样可以再构建 retrofit 时指定。

parameterHandlers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);

if (annotationAction == null) {
continue;
}

if (result != null) {
throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
}

result = annotationAction;
}

if (result == null) {
throw parameterError(p, "No Retrofit annotation found.");
}

return result;
}

作用就是解析每个参数使用的注解类型(如 Path,Query,Field 等),对每种类型进行单独的处理。

构造 HTTP 请求时,我们传递的参数都是字符串,那 Retrofit 是如何把我们传递的各种参数都转换为 String 的呢?

还是由 Retrofit 类提供 converter

Converter.Factory 除了提供上一小节提到的 responseBodyConverter,还提供 requestBodyConverterstringConverter

API 方法中除了 @Body@Part 类型的参数,都利用 stringConverter 进行转换,而 @Body 和 @Part 类型的参数则利用 requestBodyConverter 进行转换。

这三种 converter 都是通过“询问”工厂列表进行提供,而工厂我们可以在构造 Retrofit 对象时进行添加。

三种工厂( okhttp3.Call.Factory,CallAdapter.Factory 和 Converter.Factory)

OkHttpCall

OkHttpCall 实现了 retrofit2.Call,分别使用 execute() 和 equeue(Callback< T> callback) 执行同步或异步请求

同步请求

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
@Override 
public Response<T> execute() throws IOException {
okhttp3.Call call;

synchronized (this) {
// 省略部分检查代码

call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}

return parseResponse(call.execute());
}

private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();

// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();

int code = rawResponse.code();
if (code < 200 || code >= 300) {
// ...返回错误
}

if (code == 204 || code == 205) {
return Response.success(null, rawResponse);
}

ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// ...异常处理
}
}

主要步骤

  1. 创建 OkHttp3.Call
  2. 执行网络请求
  3. 解析服务器返回的数据
1
2
3
4
5
6
7
8
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}

在 createRawCall 中调用 serviceMethod.toRequest(args) 来创建 request, args 就是来自于我们之前的 parameterHandlers

okhttp3.Call call = serviceMethod.callFactory.newCall(request);
创建 okhttp3.Call, callFactory在之前已经做过分析了。

利用 execute() 来执行网络请求,这个方法是阻塞的,执行完毕之后将返回收到的响应数据。

收到响应数据之后,先进行状态码的检查,通过检查之后调用 serviceMethod.toResponse(catchingBody) 来把响应数据转化为了需要的数据类型对象。在 toResponse 函数中,之前分析的 responseConverter 也派上了用场。

异步请求

异步的不同之处在于异步交给 okhttp3.Call#enqueue(Callback responseCallback) 来实现的,并在 callback 中调用 parseResponse 解析响应数据,并转发给传入的 callback。

CallAdapter(数据转换)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}

作用就是将 retrofit2.Call R 转化为 T 。

retrofit 的 adapter模块

retrofit 内置了两个 adapterFactory

  • DefaultCallAdapterFactory 直接将参数返回
  • ExecutorCallAdapterFactory 在异步调用时在指定的Eecutor上执行回调

retrofit 子模块实现了更多的 adapterFactory

  • GuavaCallAdapterFactory
  • Java8CallAdapterFactory
  • RxJavaCallAdapterFactory

主要分析 RxJavaCallAdapterFactory

RxJavaCallAdapterFactory#get 方法中对返回值的类型进行了检查,只支持 rx.Single,rx.Completable 和 rx.Observable,这里主要关注对 rx.Observable 的支持。

RxJavaCallAdapterFactory#getCallAdapter 方法中对返回值的泛型类型进行了进一步检查

例如我们声明的返回值类型为 Observable< List< Repo>>,泛型类型就是 List< Repo>

这里对 retrofit2.Response 和 retrofit2.adapter.rxjava.Result 进行了特殊处理,有单独的 adapter 负责进行转换,其他所有类型都由 SimpleCallAdapter 负责转换。

SimpleCallAdapter#adapter

1
2
3
4
5
6
7
8
9
@Override
public <R> Observable<R> adapt(Call<R> call) {
Observable<R> observable = Observable.create(new CallOnSubscribe<>(call))
.lift(OperatorMapResponseToBodyOrError.<R>instance());
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}

创建了一个 Observable,它的逻辑由 CallOnSubscribe 类实现,同时使用了一个 OperatorMapResponseToBodyOrError 操作符,用来把 retrofit2.Response 转为我们声明的类型,或者错误异常类型。

CallOnSubscribe#call

1
2
3
4
5
6
7
@Override
public void call(final Subscriber<? super Response<T>> subscriber) { // Since Call is a one-shot type, clone it for each new subscriber. Call<T> call = originalCall.clone();

// Wrap the call in a helper which handles both unsubscription and backpressure. RequestArbiter<T> requestArbiter = new RequestArbiter<>(call, subscriber);
subscriber.add(requestArbiter);
subscriber.setProducer(requestArbiter);
}
  1. clone 了原来的 call,因为 okhttp3.Call 是只能用一次的,所以每次都是新 clone 一个进行网络请求;
  2. 创建了一个叫做 RequestArbiter 的 producer;
  3. 把这个 producer 设置给 subscriber

大部分情况下 Subscriber 都是被动接受 Observable push 过来的数据,但要是 Observable 发得太快,Subscriber 处理不过来,那就有问题了,所以就有了一种 Subscriber 主动 pull 的机制,而这种机制就是通过 Producer 实现的。

给 Subscriber 设置 Producer 之后(通过 Subscriber#setProducer 方法),Subscriber 就会通过 Producer 向上游根据自己的能力请求数据(通过 Producer#request 方法),而 Producer 收到请求之后(通常都是 Observable 管理 Producer,所以“相当于”就是 Observable 收到了请求),再根据请求的量给 Subscriber 发数据。

(不就是rxjava 背压???)

RequestArbiter#request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
public void request(long n) {
if (n < 0) throw new IllegalArgumentException("n < 0: " + n);
if (n == 0) return; // Nothing to do when requesting 0.
if (!compareAndSet(false, true)) return; // Request was already triggered.

try {
Response<T> response = call.execute();
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(response);
}
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
if (!subscriber.isUnsubscribed()) {
subscriber.onError(t);
}
return;
}

if (!subscriber.isUnsubscribed()) {
subscriber.onCompleted();
}
}

实际干活的逻辑就是执行 call.execute(),并把返回值发送给下游。

OperatorMapResponseToBodyOrError#call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
public Subscriber<? super Response<T>> call(final Subscriber<? super T> child) {
return new Subscriber<Response<T>>(child) {
@Override
public void onNext(Response<T> response) {
if (response.isSuccessful()) {
child.onNext(response.body());
} else {
child.onError(new HttpException(response));
}
}

@Override
public void onCompleted() {
child.onCompleted();
}

@Override
public void onError(Throwable e) {
child.onError(e);
}
};
}

调用 response.body() 并发送给下游。

这里,body() 返回的就是我们声明的泛型类型了

至于 Retrofit 是怎么把服务器返回的数据转为我们声明的类型的,那就看 responseBodyConverter,下面讲道。

执行流程

  1. Observable.subscribe,触发 API 调用的执行
  2. CallOnSubscribe#call,clone call,创建并设置 producer
  3. RequestArbiter#request,subscriber 被设置了 producer 之后最终调用 request,在 request 中发起请求,把结果发给下游
  4. OperatorMapResponseToBodyOrError$1#onNext,把 response 的 body 发给下游
  5. 最终就到了 subscribe 传入的回调里面了

retrofit-converters 模块

retrofit 内置 BuiltInConverters,只能处理 ResponseBody, RequestBody 和 String 类型的转化。

retrofit-converters 中的子模块则提供了 JSON,XML,ProtoBuf 等类型数据的转换功能,而且还有多种转换方式可以选择。这里主要关注 GsonConverterFactory

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
 @Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;

GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}

@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}

根据目标类型,利用 Gson#getAdapter 获取相应的 adapter,转换时利用 Gson 的 API 即可.

至于Gson就又是一篇文章了。

参考大神piasy