Retrofit流程分析详解

在之前的文章中介绍了《在kotlin协程中使用自定义CallAdapter处理错误》,既然选择了它,当然得先全面了解一下。 先下载一下源码,搭建一下环境,也没啥好说的,我下载的是2.11.0 版本的代码,使用的 IDEA2023.3.6。这都是小事情,只要能有代码跳转功能就好。首次配置需要下载相应依赖,时间会长一些,这不重要。等配置完成后,找到 simple module,有各种各样的示例代码。是可以直接运行的。

创建Retrofit对象

我们先从如何创建的Retrofit对象开始 先看一下我们可以设置哪些参数,撸一下源码,找一下Retrofit.Builder

设置OkHttpClient

这里的OkHttpClient实现了Call.Factory接口

Java 复制代码
public Builder client(OkHttpClient client) {
  return callFactory(Objects.requireNonNull(client, "client == null"));
}
public Builder callFactory(okhttp3.Call.Factory factory) {
  this.callFactory = Objects.requireNonNull(factory, "factory == null");
  return this;
}

设置 baseUrl

Java 复制代码
public Builder baseUrl(URL baseUrl) {
  Objects.requireNonNull(baseUrl, "baseUrl == null");
  return baseUrl(HttpUrl.get(baseUrl.toString()));
}
public Builder baseUrl(String baseUrl) {
  Objects.requireNonNull(baseUrl, "baseUrl == null");
  return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
  Objects.requireNonNull(baseUrl, "baseUrl == null");
  List<String> pathSegments = baseUrl.pathSegments();
  if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
    throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
  }
  this.baseUrl = baseUrl;
  return this;
}

序列化和反序列化

Java 复制代码
public Builder addConverterFactory(Converter.Factory factory) {
  converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
  return this;
}

支持'Call'对象之外的返回类型

Java 复制代码
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
  callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
  return this;
}

调用 callBack 时使用的Executor

Java 复制代码
public Builder callbackExecutor(Executor executor) {
  this.callbackExecutor = Objects.requireNonNull(executor, "executor == null");
  return this;
}

是否提前验证接口中定义的方法

Java 复制代码
public Builder validateEagerly(boolean validateEagerly) {
  this.validateEagerly = validateEagerly;
  return this;
}

调用 build()方法创建 Retrofit 对象

Java 复制代码
public Retrofit build() {
  if (baseUrl == null) {
      throw new IllegalStateException("Base URL required.");
  }

  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
      callFactory = new OkHttpClient();
  }

  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
      callbackExecutor = Platform.callbackExecutor;
  }

  BuiltInFactories builtInFactories = Platform.builtInFactories;

  // Make a defensive copy of the adapters and add the default Call adapter.
  List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  List<? extends CallAdapter.Factory> defaultCallAdapterFactories =
  builtInFactories.createDefaultCallAdapterFactories(callbackExecutor);
  callAdapterFactories.addAll(defaultCallAdapterFactories);

  // Make a defensive copy of the converters.
  List<? extends Converter.Factory> defaultConverterFactories =
  builtInFactories.createDefaultConverterFactories();
  int defaultConverterFactoriesSize = defaultConverterFactories.size();
  List<Converter.Factory> converterFactories =
  new ArrayList<>(1 + this.converterFactories.size() + defaultConverterFactoriesSize);

  // Add the built-in converter factory first. This prevents overriding its behavior but also
  // ensures correct behavior when using converters that consume all types.
  converterFactories.add(new BuiltInConverters());
  converterFactories.addAll(this.converterFactories);
  converterFactories.addAll(defaultConverterFactories);

  return new Retrofit(
      callFactory,
      baseUrl,
      unmodifiableList(converterFactories),
      defaultConverterFactoriesSize,
      unmodifiableList(callAdapterFactories),
      defaultCallAdapterFactories.size(),
      callbackExecutor,
      validateEagerly);
}
  1. 首先检查是否设置了 baseUrl,没设置直接抛异常
  2. 设置callFactory,默认为OkHttpClient
  3. 设置callbackExecutor默认为platform.defaultCallbackExecutor(),Android平台为MainThreadExecutor,其他平台为 null。这里的 AndroidMainExecutor 只是简单的使用 handler 转发到主线程
Java 复制代码
final class AndroidMainExecutor implements Executor {
  private final Handler handler = new Handler(Looper.getMainLooper());

  @Override
  public void execute(Runnable r) {
      handler.post(r);
  }
}
  1. callAdapterFactories 默认添加 platform.defaultCallAdapterFactories,返回值为DefaultCallAdapterFactory,之后在 kotlin 中使用密闭类代替 callback 时就是抄的这个类中的方法
  2. converterFactories ○ 先添加 new BuiltInConverters() ○ 再添加自定义的 ○ 最后添加platform.defaultConverterFactories() 默认是空的 这样就配置好的 Retrofit 对象

如何发送请求

我们在定义网络请求时是这么写的

定义网络请求

Java 复制代码
  public interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
  }

创建GitHub对象 和发送请求

Java 复制代码
  // Create an instance of our GitHub API interface.
  GitHub github = retrofit.create(GitHub.class);
  // Create a call instance for looking up Retrofit contributors.
  Call<List<Contributor>> call = github.contributors("square", "retrofit");
  // Fetch and print a list of the contributors to the library.
  List<Contributor> contributors = call.execute().body();

重点在我们调用retrofit.create方法时用到的动态代理商

Java 复制代码
  public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    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);
                }
                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);
              }
            });
  }

validateServiceInterface

创建 Github 对象时使用了动态代理,不过在创建之前,先调用了validateServiceInterface(service);

Java 复制代码
private void validateServiceInterface(Class<?> service) {
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }

    Deque<Class<?>> check = new ArrayDeque<>(1);
    check.add(service);
    while (!check.isEmpty()) {
      Class<?> candidate = check.removeFirst();
      if (candidate.getTypeParameters().length != 0) {
        StringBuilder message =
            new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
        if (candidate != service) {
          message.append(" which is an interface of ").append(service.getName());
        }
        throw new IllegalArgumentException(message.toString());
      }
      Collections.addAll(check, candidate.getInterfaces());
    }

    if (validateEagerly) {
      Reflection reflection = Platform.reflection;
      for (Method method : service.getDeclaredMethods()) {
        if (!reflection.isDefaultMethod(method)
            && !Modifier.isStatic(method.getModifiers())
            && !method.isSynthetic()) {
          loadServiceMethod(service, method);
        }
      }
    }
  }

先检查 Github 类是不是 Interface,接着定义一个双端队列,对当前接口及其父接口进行递归检查,这里是不支持泛型参数的。 在接下来判断一下在创建 Retrofit 时传入的validateEagerly参数,如果是 true,并且声明的方法不是默认、不是静态、不是合成方法,则调用loadServiceMethod方法解析接口中声明的方法。

loadServiceMethod

首先调用ServiceMethod.parseAnnotations(this, service, method);,先从缓存的map中获取有没有已经解析好的ServiceMethod。如果没有则调用ServiceMethod.parseAnnotations(this, method)方法进行解析。

第一步创建requestFactory对象

调用了 RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, service, method); ,解析了例如请求方式(即 POST 还是 GET 等请求),请求头,contentType 等等参数并返回了一个RequestFactory对象

第二步创建HttpServiceMethod子类CallAdapted

接着通过HttpServiceMethod的静态方法parseAnnotations进一步解析,入参有Retrofit对象,Method对象和刚才创建的RequestFactory 对象。HttpServiceMethod继承自ServiceMethod,但也是个抽象类,这个类提供的parseAnnotations方法的主要内容是进一步解析,并通过createCallAdapter创建适配器、通过createResponseConverter创建转换器,最后利用RequestFactory对象,OkHttp对象,转换器对象,适配器对象创建了一个CallAdapted类型的对象并返回。

创建适配器

如果我们前面没有调用addCallAdapterFactory(CallAdapter.Factory factory)添加自定义的Factory的话,这里返回的是默认的DefaultCallAdapterFactory对象。 在该类的adapt方法中返回的CallAdapter对象中,先判断了executor是不是空,这里的executor就是在创建Retrofit时调用public Builder callbackExecutor(Executor executor)方法时传入的对象,前面也说过,在**Android(Dalvik)**平台上默认是AndroidMainExecutor,其他平台默认为空。

简单讲,DefaultCallAdapterFactory大致如下

Java 复制代码
class DefaultCallAdapterFactory extends CallAdapter.Factory {
    @Override
  public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }
}

static final class ExecutorCallbackCall<T> implements Call<T> {
   ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
    //。。。。一系列的方法,除了enqueue(final Callback<T> callback)方法外,都是调用delegate中对应的方法
}
创建转换器

我们在使用的时候一般会传入一个ConverterFactory对象,比如MoshiConverterFactory、GsonConverterFactory等。最主要的就两个方法 responseBodyConverter and requestBodyConverter.在调用HttpServiceMethod.createResponseConverter时,兜兜转转最终还是调用了 Retrofit.nextCallAdapter方法,从我们一开始构建的 Retrofit 对象中查找对应的转换器

创建CallAdapted对象

这里直接调用的构造方法

Java 复制代码
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);

注意这里传入的callAdapter对象就是前面提到的调用createCallAdapter返回的默认DefaultCallAdapterFactory示例。 CallAdapted类是HttpServiceMethod的子类,实现了父类的抽象方法adapt。而HttpServiceMethod又实现了ServiceMethod的抽象方法invoke,在invoke方法里调用了adapt方法。

loadServiceMethod过程总结

所以前面说到的加载过程(loadServiceMethod),最终就是返回了一个CallAdapted类型的对象,并存到缓存中。接下去就是调用了CallAdapted对象的invoke方法,显然最终调用了CallAdapted自身的adapt方法。CallAdapted提供的adapt方法里就一句,那就是调用适配器的adapt方法,并返回一个值。这个值就是我们定义的接口类型的代理对象.之后调用调用定义的接口方法获取到Call对象,调用enqueue异步执行;调用execute同步执行;

invoke过程

前面知道了loadServiceMethod返回的是一个CallAdapted对象,然后紧接着调用了invoke方法。但CallAdapted并没有重写该方法,所以实际上还是调用的HttpServiceMethod类中的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);
  }

接着调用了adapt(call, args)方法,这个方法就需要子类实现了,这里的子类是CallAdapted,在CallAdapted中接着调用

Java 复制代码
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
  return callAdapter.adapt(call);
}

该方法中的callAdapter对象就是前面提到的DefaultCallAdapterFactory.get方法中返回的CallAdapter,调用了该对应的adapt方法。在上面的介绍的创建适配器 小结中提到,在**Android(Dalvik)**平台上默认有AndroidMainExecutor,其他平台默认为空。所以在没有额外添加callbackExecutor的情况下,Android 平台上返回的是ExecutorCallbackCall,在其他平台上默认返回的就是参数中的call对象,也就是retrofit2.OkHttpCall。 这个对象也就是我们调用接口中的方法返回的对象。

发送请求

上面提到在 Android 平台上会返回ExecutorCallbackCall对象,其他平台返回retrofit2.OkHttpCall对象。但在创建ExecutorCallbackCall 对象的时候也会将retrofit2.OkHttpCall传进去,在调用各种方法的时候还是调用的retrofit2.OkHttpCall对象的方法,只不过在调用void enqueue(Callback<T> callback);方法的callback回调中使用callbackExecutor将回调切换回主线程而已。

在调用retrofit2.OkHttpCallenqueue或者execute方法时,会调用createRawCall方法创建一个okhttp3.Call对象,实际上的网络请求还是 okhttp 发出的。

Java 复制代码
  private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(instance, args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

这里的requestFactory是上面提到的parseAnnotations时创建的RequestFactory对象,包含了部分请求信息。这里又用它创建了okhttp3.Request对象。创建好之后接着就创建了okhttp3.Call对象,接下来就是调用enqueue或者execute方法发送请求。 当请求数据返回时,会调用parseResponse(okhttp3.Response rawResponse)方法,最终调用的是responseConverter.convert(catchingBody)方法,这里的responseConverter就是我们在创建Retrofit对象调用addConverterFactory时传入的解析方法. 至此,完成了一次网络请求。


以上

相关推荐
还鮟1 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡3 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi003 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil5 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你5 小时前
Android View的绘制原理详解
android
移动开发者1号8 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号8 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best13 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk13 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭17 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin