在Android开发中,我们在面临网络请求相关需求时,通常不会直接使用OkHttp,而是使用封装过更加方便的Retrofit。今天带大家一起看看Retrofit相关源码,学习源码的思路,面试中也可以讲一讲。
我认为读源码需要有一个明确的目标,源码中的内容太多,一行行看不但难以理解还会扰乱思路,我按照以下两个方向来阅读源码。
- Retrofit主流程
- 如何实现线程切换(CallAdapter)
Retrofit主流程
kotlin
val retrofit: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.build()
}
retrofit.create(UserApiService::class.java)
fun demoBasicEnqueue() {
val call = userApiCall.getUserByIdCall(42L)
call.enqueue(object : Callback<UserResponse> {
override fun onResponse(call: Call<UserResponse>, response: Response<UserResponse>) {
}
override fun onFailure(call: Call<UserResponse>, t: Throwable) {
}
})
}
先给出一段最简单的Retrofit的使用代码,UserApiService是我们定义的接口文件。在调用retrofit.create后调用enqueue进行网络请求。
首先先明确我们的目标 ------ 搞明白retrofit的具体流程。但是直接从call.enqueue中点进去看会发现里面都是抽象类和接口,先记住是Retrofit中的Call接口的enqueue方法。我们先从 retrofit.create 方法中进入,可以看到如下代码:
java
public <T> T create(final Class<T> service) {
validateServiceInterface(service); // 对Class类进行验证(如是否是接口,是否包含泛型)
return (T)
Proxy.newProxyInstance( // 动态代理
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable 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); // Object的方法直接忽略
}
args = args != null ? args : emptyArgs;
Reflection reflection = Platform.reflection;
return reflection.isDefaultMethod(method)
? reflection.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(service, method).invoke(proxy, args);
}
});
}
动态代理:可以理解为在程序运行时,创建了一个实现了指定接口的代理类,类中方法的实现委派给传入的
InvocationHandler,最终具体的实现由InvocationHandler的invoke执行
忽略掉前面的校验,我们直接看核心方法 loadServiceMethod(service, method).invoke(proxy, args)
java
ServiceMethod<?> loadServiceMethod(Class<?> service, Method method) {
while (true) {
Object lookup = serviceMethodCache.get(method);
// 从serviceMethodCache(ConCurrentHashMap)中取缓存
if (lookup instanceof ServiceMethod<?>) {
return (ServiceMethod<?>) lookup;
}
if (lookup == null) {
Object lock = new Object();
synchronized (lock) {
lookup = serviceMethodCache.putIfAbsent(method, lock);
if (lookup == null) {
try {
// 如果缓存中没有,调用 ServiceMethod.parseAnnotations 方法
result = ServiceMethod.parseAnnotations(this, service, method);
} catch (Throwable e) {
serviceMethodCache.remove(method);
throw e;
}
//存入缓存
serviceMethodCache.put(method, result);
return result;
}
}
}
synchronized (lookup) {
Object result = serviceMethodCache.get(method);
if (result == null) {
continue;
}
return (ServiceMethod<?>) result;
}
}
}
可以看到loadServiceMethod是一个带有缓存的方法,返回一个ServiceMethod并且在外层调用invoke方法(记住这一点) ,我们主要关注ServiceMethod.parseAnnotations中的HttpServiceMethod.parseAnnotations方法
java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Class<?> service, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, service, method);
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.");
}
// 关注这个
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
再进入HttpServiceMethod.parseAnnotations中我们直接看最后的return,可以看到如下代码:
java
if (!isKotlinSuspendFunction) { // 判断是否是Kotlin挂起方法
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable,
continuationIsUnit);
}
兼容Kotlin挂起函数的代码就在这里,但现在我们先不关注这一块,回到一开始我们的目标弄明白Retrofit的主要流程。到HttpServiceMethod 类中,可以发现这个类是继承自ServiceMethod的,其自然也就重写了invoke方法:
java
@Override
final @Nullable ReturnT invoke(Object instance, Object[] args) {
Call<ResponseT> call =
new OkHttpCall<>(requestFactory, instance, args, callFactory, responseConverter);
return adapt(call, args);
}
这个Call就是上文提及的Call.enqueue的Call,返回的OkHttpCall也就是实现类了Call接口的对象。再次点进去查看源码:
java
@Override
public void enqueue(final Callback<T> callback) {
...
okhttp3.Call call;
....
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
到这一步已经真相大白了,其实内部是调用的OkHttp3的enqueue的方法。
到此为止可以总结Retrofit的流程:Retrofit通过动态代理生成代理类 ------ InvocationHandler处理方法 ------ 调用接口返回Retrofit中的Call ------ Retrofit中的Call会调用OkHttp3中的Call实现真正的网络请求

如何实现线程切换
回到上文中的invoke方法,看到返回的实际上是被adapt包裹的call,这里先记住这个adapt方法
java
@Override
final @Nullable ReturnT invoke(Object instance, Object[] args) {
Call<ResponseT> call =
new OkHttpCall<>(requestFactory, instance, args, callFactory, responseConverter);
return adapt(call, args);
}
再回到HttpServiceMethod.parseAnnotations源码中,可以看到最后返回的是一个CallAdapted,但是这个adapter实际上是继承HttpServiceMethod的类,真正的adapter在传参中,也就是createCallAdapter创建出来的callAdapter
java
...
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
...
if (!isKotlinSuspendFunction) { // 判断是否是Kotlin挂起方法
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable,
continuationIsUnit);
}
java
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
// 是继承HttpServiceMethod 的类,真正的callAdapter在传参中
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
//这里会调用adapt方法,也就是说之前的adapt做了什么实际上看真实的callAdapter中的adapt方法即可
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
我们再进入createCallAdapter中,这里层级较多,不给大家一一展示,最后会到Retrofit.nextCallAdapter中:
java
public CallAdapter<?, ?> nextCallAdapter(
@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
Objects.requireNonNull(returnType, "returnType == null");
Objects.requireNonNull(annotations, "annotations == null");
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
StringBuilder builder =
new StringBuilder("Could not locate call adapter for ").append(returnType).append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
callAdapterFactories 是一个CallAdapter.Factory的List,上述的代码简单来说就是从这个List取CallAdapter。我们需要的不是取值,而是赋值,因此从callAdapterFactories的赋值位置入手。在Retrofit.Builder中可以看到 DefaultCallAdapterFactory被add到List中
java
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) { // 之前执行的adapt在这里
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
java
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override
public void enqueue(final Callback<T> callback) { //这里又包装了一层enqueue
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute( // 对结果的回调进行线程的切换
() -> {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on
// cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
上面的源码很简单,adapt实际上在Call的基础上又包装了一层进行返回,而这层包装的作用就是将回调都放在线程池中进行处理。那为什么要放到线程池中处理呢?这次切线程有什么意义呢?我们注意Executor callbackExecutor这个参数,往回看
java
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = Platform.callbackExecutor;
}
java
final class Platform {
static final @Nullable Executor callbackExecutor;
static final Reflection reflection;
static final BuiltInFactories builtInFactories;
static {
switch (System.getProperty("java.vm.name")) {
case "Dalvik": // 返回主线程的线程池
callbackExecutor = new AndroidMainExecutor();
if (SDK_INT >= 24) {
reflection = new Reflection.Android24();
builtInFactories = new BuiltInFactories.Java8();
} else {
reflection = new Reflection();
builtInFactories = new BuiltInFactories();
}
break;
Platform 是一个判断平台的参数,作为Android开发我们可以看到返回的实际上是主线程的线程池。到这一步线程切换的源码实际上已经分析完毕了。
总结一下:线程切换实际上是Retrofit自带的功能,通过对Call的再次包装,将请求结果的回调抛出到主线程池。

新人第一次写文章,大家有什么建议欢迎留言 ^ ^