在前面的两篇文章中,我们已经对 Retrofit 的注解解析、动态代理、网络请求和响应处理机制有了一定的了解。在这篇文章中,我们将深入分析 Retrofit 的 Call 逻辑,并介绍 Retrofit 的扩展机制。
一、Call 逻辑分析
Call 是 Retrofit 中最基本的操作单元,它代表一个 HTTP 请求。在 Retrofit 中,我们通过接口定义请求的方式,并通过动态代理生成接口的实现类。这个实现类中的方法都会返回一个 Call 对象,通过这个对象我们可以发起网络请求,并获得响应结果。
Retrofit 的 Call 逻辑可以用以下代码来描述:
public interface Call<T> {
Response<T> execute() throws IOException;
void enqueue(Callback<T> callback);
void cancel();
boolean isExecuted();
boolean isCanceled();
Call<T> clone();
}
在这个接口中,我们可以看到 Retrofit 定义了五个方法,分别是 execute
、enqueue
、cancel
、isExecuted
和isCanceled
。我们来逐一分析这些方法的作用。
execute 方法
execute
方法用于同步发起 HTTP 请求,当我们调用execute()
方法时,它会立即发起网络请求,并且阻塞当前线程直到请求结束,最后返回一个响应对象Response
。这种方式适用于简单的网络请求,但不适合于在主线程中执行请求,因为会阻塞 UI 线程。
以下是execute()
方法的部分代码:
@Override
public Response<T> execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
}
captureCallStackTrace();
try {
client.dispatcher().executed(this);
Response<T> result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
throw timeoutExit(e);
} finally {
client.dispatcher().finished(this);
}
}
上述代码中,我们可以看到该方法首先会检查当前请求是否已经执行过,如果已经执行过则会抛出一个异常。然后会将该请求加入到Dispatcher
中的执行队列中。接下来会调用getResponseWithInterceptorChain()
方法来获取响应结果。如果结果为null,则表示请求已经被取消,否则返回响应结果。最后,会将该请求从执行队列中移除。
enqueue 方法
enqueue
方法用于异步发起 HTTP 请求,它会在后台线程中发起网络请求,并在请求结束后将结果返回到主线程中。因此,enqueue()
方法适用于在主线程中执行网络请求。
以下是enqueue()
方法的部分代码:
@Override
public void enqueue(Callback<T> callback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(callback));
}
上述代码中,我们可以看到该方法首先会检查当前请求是否已经执行过,如果已经执行过则会抛出一个异常。然后会将该请求封装成一个AsyncCall
对象,加入到Dispatcher
中的异步队列中。
AsyncCall
继承自RealCall
,它实现了Runnable
接口,表示可以在后台线程中执行。在AsyncCall
中,我们可以看到它会在后台线程中执行网络请求,并将结果通过Callback
回调返回到主线程中。
final class AsyncCall extends RealCall.AsyncCall {
private final Callback<T> responseCallback;
AsyncCall(Callback<T> responseCallback) {
super();
this.responseCallback = responseCallback;
}
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response<T> response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
@Override public String toString() {
return RealCall.this.toString();
}
}
在AsyncCall
中,首先会调用getResponseWithInterceptorChain()
方法来获取响应结果。如果请求被取消,则会调用onFailure()
方法将结果返回到主线程中。否则,会调用onResponse()
方法将结果返回到主线程中。无论请求成功或失败,都会调用finished()
方法将该请求从异步队列中移除。
cancel 方法
cancel
方法用于取消正在执行的请求。如果请求已经完成或已经取消,则该方法不会有任何效果。
isExecuted 方法
isExecuted
方法用于判断请求是否已经执行。如果已经执行,则返回true,否则返回false。
isCanceled 方法
isCanceled
方法用于判断请求是否已经取消。如果已经取消,则返回true,否则返回false。
clone 方法
clone
方法用于创建一个当前 Call 对象的副本。这个方法一般用于发起多次相同的请求。
以上这些方法就构成了 Retrofit 的 Call 逻辑。在使用 Retrofit 时,我们一般会通过execute
或enqueue
方法发起 HTTP 请求,并通过传入的Callback
对象来处理响应结果。
二、扩展机制
Retrofit 是一个非常灵活的网络请求库,它提供了很多扩展机制,让我们可以根据自己的需要来定制请求和响应处理逻辑。下面介绍一些常用的扩展机制。
Converter
Converter 用于将 HTTP 请求和响应的数据类型转换成 Java 对象。Retrofit 默认提供了两种 Converter:GsonConverter
和JacksonConverter
,它们分别使用Gson
和Jackson
库将数据类型转换成Java
对象。如果我们需要使用其他类型的转换库,也可以自定义 Converter 来实现。
下面是一个自定义 Converter 的示例:
public class MyConverter implements Converter<ResponseBody, MyObject> {
private Gson gson;
public MyConverter(Gson gson) {
this.gson = gson;
}
@Override
public MyObject convert(ResponseBody value) throws IOException {
try {
String json = value.string();
MyObject obj = gson.fromJson(json, MyObject.class);
return obj;
} finally {
value.close();
}
}
}
在上面的示例中,我们定义了一个MyConverter
类,它实现了Converter
接口,用于将ResponseBody
类型的响应数据转换成MyObject
类型的Java
对象。在convert
方法中,我们使用自己定义的转换逻辑来实现数据类型的转换。
Interceptor
Interceptor 用于对 HTTP 请求进行拦截和处理。在 Retrofit 中,我们可以通过 Interceptor 来对请求添加头信息、对响应进行缓存、打印请求日志等操作。Retrofit 提供了两种 Interceptor:OkHttpInterceptor
和RetrofitInterceptor
,它们分别用于拦截 OkHttp 的请求和 Retrofit 的请求。我们也可以自定义 Interceptor 来实现自己的拦截逻辑。
下面是一个自定义 Interceptor 的示例:
public class MyInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
// 在这里可以对请求进行拦截和处理
Request request = chain.request();
Response response = chain.proceed(request);
// 在这里可以对响应进行处理
return response;
}
}
在上面的示例中,我们定义了一个MyInterceptor
类,它实现了Interceptor
接口,用于对请求和响应进行拦截和处理。在intercept
方法中,我们可以对请求进行处理,然后使用chain.proceed(request)
方法将请求传递给下一个拦截器或处理器,最终获得响应结果并进行处理。
CallAdapter
CallAdapter 用于将 Call 对象转换成另一种类型的对象。在 Retrofit 中,我们可以通过 CallAdapter 将 Call 对象转换成 RxJava 的 Observable 对象,也可以将 Call 对象转换成 LiveData 对象。Retrofit 提供了两种CallAdapter:RxJavaCallAdapter
和LiveDataCallAdapter
,它们分别用于将 Call 对象转换成 RxJava 的 Observable 对象和 LiveData 对象。我们也可以自定义 CallAdapter 来实现自己的转换逻辑。
下面是一个自定义 CallAdapter 的示例:
public class MyCallAdapter<T> implements CallAdapter<T, MyResult<T>> {
@Override
public Type responseType() {
// 返回响应数据的类型
return new ParameterizedTypeImpl(MyResult.class, new Type[]{T.class});
}
@Override
public MyResult<T> adapt(Call<T> call) {
// 在这里可以对Call对象进行处理,并返回自定义的结果对象
try {
Response<T> response = call.execute();
return new MyResult<>(response.body(), response.code(), response.message());
} catch (IOException e) {
return new MyResult<>(e);
}
}
}
在上面的示例中,我们定义了一个MyCallAdapter
类,它实现了CallAdapter
接口,用于将Call
对象转换成MyResult
对象。在responseType
方法中,我们返回了响应数据的类型,它是一个ParameterizedTypeImpl
类型的对象,用于表示MyResult<T>
类型。在adapt
方法中,我们对Call
对象进行处理,并返回自定义的MyResult
对象,它包含了响应数据、状态码和错误信息。
总结
在本文中,我们深入分析了 Retrofit 的核心源码,特别是 Call 逻辑的实现细节,以及 Retrofit 的三个扩展机制:Converter、Interceptor 和 CallAdapter。
通过本文的学习,我们可以更加深入地理解 Retrofit 的工作原理,并可以根据需求自定义扩展 Retrofit 的功能。同时,本文提供了三个扩展机制的示例代码,可以帮助读者更加深入地了解 Retrofit 的扩展机制的使用。