Retrofit 源码分析

在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,最终具体的实现由InvocationHandlerinvoke执行

忽略掉前面的校验,我们直接看核心方法 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的再次包装,将请求结果的回调抛出到主线程池。

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

相关推荐
xiaoduzi19911 小时前
Android 线程池总结
android
YIN_尹1 小时前
【Linux系统编程】基础IO第二讲——文件描述符
android·linux·服务器
朝星1 小时前
Android开发[10]:性能优化之内存
android·kotlin
像风一样自由20202 小时前
量化压缩实战:INT8 / INT4 / AWQ / GPTQ 全面对比
android·人工智能·语言模型·大模型
brycegao3212 小时前
Android MVI进阶:纯原生实现Slot化可插拔架构
android·kotlin·架构设计·mvi·viewmodel
2601_961194023 小时前
27考研资料|百度网盘|夸克网盘
android·xml·考研·ios·iphone·xcode·webview
故渊at3 小时前
第二板块:Android 四大组件标准化学理 | 第十篇:ContentProvider 数据共享与 SQLite 引擎
android·jvm·数据库·sqlite·contentprovider
Kapaseker3 小时前
你遇到过 Kotlin 协程中的竞争问题吗?
android·kotlin
与水同流3 小时前
Android13 AIDL HAL服务实现Demo
android·hal·aidl