Retrofit流程极简解析

617 阅读3分钟

以SandwichDemo为例子来解析。github地址

创建Retrofit

  • private val retrofit: Retrofit = Retrofit.Builder()
    .client(okHttpClient)
    .baseUrl(
      "https://gist.githubusercontent.com/skydoves/aa3bbbf495b0fa91db8a9e89f34e4873/raw/a1a13d37027e8920412da5f00f6a89c5a3dbfb9a/"
    )
    .addConverterFactory(GsonConverterFactory.create())
    
    /* asynchronous supports */
    // .addCallAdapterFactory(DataSourceCallAdapterFactory.create())
    
    /* coroutines supports */
    .addCallAdapterFactory(CoroutinesResponseCallAdapterFactory.create())
    //.addCallAdapterFactory(CoroutinesDataSourceCallAdapterFactory.create())
    .build()
    

    创建接口类

    val disneyService: DisneyCoroutinesService = retrofit.create(DisneyCoroutinesService::class.java)
    

    获取接口返回的数据

    val apiResponse:ApiResponse<List<Poster>> = disneyService.fetchDisneyPosterList()
    

    就是这么简单,数据获取完成


细分流程解析

    1. 创建Retrofit。这里使用了创建者模式,通过Retrofit.Builder来创建Retrfofit实例,一般项目里都会做成单例
    2. Builder().client(OkHttpClient client)设置网络请求的最终调用者,这里和OkHttp是绝配
    3. baseUrl(Url baseUrl)设置baseUrl链接
    4. addConverterFactory(Converter.Factory factory)添加网络参数和返回类的转换器,例如Gson,Moshi
    5. addCallAdapterFactory(CallAdapter.Factory factory)添加接口请求结果的转换器
    6. build()方法中,会通过platform.defaultCallAdapterFactories(callbackExecutor)来添加默认的CallAdapter.Factory转换器和我们自定义的转换器。而ConvertorFactory转换器,默认加入new BuiltInConverters()和平台默认转换器platform.defaultConverterFactories()以及我们自定义的转换器
  • 通过Retrofit创建接口类 1.调用create(Class<T> service)方法来创建对应的接口类

    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              private final Platform platform = Platform.get();
              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;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
    

    这里就是通过动态代理来。动态代理的理论网上很多,可以自己搜索;简单说下,就是比如代理的接口类,调用它的方法时候,会进入到动态代理类里InvocationHandlerinvoke()中,这里参数有method提供Method的各种方法,args参数提供方法的各个参数。这里就是完全代理了接口方法,来自己实现,这里思想多大,舞台就有多大。

  • invoke方法解析

    1. 解析loadServiceMethod(method).invoke(args)loadServiceMethod()方法返回ServiceMethod抽象类,实际是HttpServiceMethod类。
    2. 核心方法HttpServiceMethod.parseAnnotations方法调用并返回HttpServiceMethod类,这里是核心解析方法;上面的invoke(args)方法最终是调用了HttpServiceMethod类的invoke方法,最终是调用如下:
     @Override
    final @Nullable ReturnT invoke(Object[] args) {
        Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
        return adapt(call, args);
    }
    

    这里记住这个类OkHttpCall 3. 解析HttpServiceMethod<ResponseT, ReturnT>.parseAnnotations()方法: 这里会通过RequestFactory来解析参数和返回值,其中 java if (Utils.getRawType(parameterType) == Continuation.class) { isKotlinSuspendFunction = true; return null; } 这个解析判断是否是suspend函数。 这里会根据是否挂起函数来确定不同的返回值。 继续:根据是否是挂起函数,来获取对应的adapterType,即类似Call<UserData>里的UserData类型,或者suspendUserData返回值类型。

    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    

    这里通过返回类型,来匹配我们加入的CallAdapter来进行返回的Response的包装或者逻辑处理

    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
    

    这里通过responseType来获取我们添加的返回结果转换器,比如GsonFactory,MothiFactory来 4.

        if (!isKotlinSuspendFunction) {
          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);
        }
    

    这里会返回最终的各式各样的HttpMethod的实现类 如果非suspend函数,则直接返回CallAdapter这里,Java代码非协程一般都是这种情况; 如果是suspend函数且返回值为Response类型的,则返回SuspendForResponse 其余的suspend函数情况,则返回SuspendForBodykotlin+协程里一般是这种情况 5. 分析CallAdapterSuspendForBody的区别,最大区别,就是Suspend会再adapt里自动调用OkHttp的请求接口方法并返回对应的Response,而CallAdapter则不会,而是需要使用者自己去调用。

    至此,简略版的Retrofit流程已经梳理完毕

    我们自己可以自定义的部分:ConverterFactoryCallFactory这里官方都给了默认的和常用的,例如Converter转换类就有gson,guava,jackson,moshi,jaxb....;而默认的CallFactory,除了库里自带的默认的DefualtCallFactory,还有官方写的库:guava,java8,rxjava,rxjava2,rxjava3,scala,这里常用的是rxjava2,rxjava3,还有例如我现在用的Sandwich库里封装的CoroutinesResponseCallAdapterFactorykotlin协程配合起来非常好用