【一起学习Android开源框架】Retrofit源码解析(五)-RxjavaCallAdapterFacotory内部构造与工作原理

733 阅读7分钟

前文我们分析了Retrofit中builder内部类的成员变量的作用以及创建的一些方法baseUrl,addConverterFactory, addCallAdapterFactory,详细可以看下上一篇文章

【一起学习Android开源框架】Retrofit源码解析-2(第四部分))

好的,话不多接下来我们继续分析Retrofit,Let's go


build方法创建流程

我们需要调用build方法来完成retroifit对象创建,接下来我们看看这个方法到底做了哪些工作呢? 来看下它的源码

  • 首先它会对baseUrl进行一个非空的判断,如果是空的时候会抛出异常

       if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
          }
    
  • baseUrl不为空的时候,首先先进行创建callFactory网络请求指示器,用于产生网络的call工厂,也就是实际的http请求,那么它为空的时候就是默认创建OkhttpClient,其实就已经表明了Retrotfit就是默认使用Okhttp进行网络请求的,这是第一步

     okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {
            callFactory = new OkHttpClient();
          }
    
  • 第二步,这里主要是初始化回调方法执行器,下面callbackExecutor主要用在异步请求,大家知道这个时候肯定会在子线程做耗时操作,但是最后都要回到UI线程进行显示,此时callbackExecutor就派上了用场;如果它是空的话,会默认提供一个回调执行器,在platform中的defaultCallbackExecutor,其实就是主线程的executor,后面再详细说明

        Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
          }
    
  • 第三步,会创建一个adapterFactoriesArrayList,用于配置网络请求适配器工厂,然后再将平台默认的adapterFactory添加这个集合当中

     // Make a defensive copy of the adapters and add the default Call adapter.
          List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
          callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
    
  • 接着第四步,和上面差不多方式,也是创建一个ArrayList,配置数据转换器的工厂,它传入的成员变量就是我们前面配置的convertFactories

       // Make a defensive copy of the converters.
          List<Converter.Factory> converterFactories =
              new ArrayList<>(
                  1 + this.converterFactories.size() + platform.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(platform.defaultConverterFactories());
    
  • 最后会将前面创建好的所有变量会传入到Retrofit对象中进行重建

       return new Retrofit(
              callFactory,
              baseUrl,
              unmodifiableList(converterFactories),
              unmodifiableList(callAdapterFactories),
              callbackExecutor,
              validateEagerly);
    

总结一下build方法,其实就是通过内部类,将Retrofit所有成员变量逐个配置,最后将Retrofit对象重建

上面我们已经了解了整体Retrofit构建流程,接下来我们来具体了解网络请求适配器和数据转换工厂的具体原理,首先我们来看当时创建的时候所设置的RxJavaCallAdapterFactory适配器

RxjavaCallAdapterFacotory内部构造与工作原理

首先我们来看下RxjavaCallAdapterFacotry内部的源码,可以看到它是继承Factory类,可以看到,追本朔源,这个Factory其实定义在CallAdapter当中

public final class RxJavaCallAdapterFactory extends CallAdapter.Factory { 
  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static RxJavaCallAdapterFactory createWithScheduler(Scheduler scheduler) {
    if (scheduler == null) throw new NullPointerException("scheduler == null");
    return new RxJavaCallAdapterFactory(scheduler, false);
      .....
  }

关于这个CallAdapter我想我们还是有必要去梳理下它的流程,它是如何在Retrofit当中工作的?先看下它的源码

public interface CallAdapter<R, T> {
​
  Type responseType();
​
  T adapt(Call<R> call);
 
  public abstract @Nullable CallAdapter<?, ?> get(
        Type returnType, Annotation[] annotations, Retrofit retrofit);
​
  protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}
​

其实不难看出,callAdapter它的作用就是把Call<T>泛型转换成java对象;值得注意下,这里的Call对象和Okhttp当中其实是不一样的,Retrofit中的Call是对OkhttpCall进行了封装,所以说我们通过Retrofit进行网络请求都是通过Okhttp来,可以理解为Retorfit是为Okhttp封装的一层壳

但是Call<T>泛型转换成java对象,不是直接转换的,是有个过程的,可以看下下面的流程图

callAdapter.png

我们创建好Retrofit中的Call对象,然后发送一个http请求,拿到服务器返回给我们的数据,这时候就通过converter数据转换器才转换成java对象

回到代码,来看下callAdapter具体做了什么

  1. 先看下responseType()这个方法,有一个返回值类型Type,它的作用就是用于返回http,返回的是解析后的类型,什么意思呢,简单来说,这里的Type并不是接口返回的类型,而是它返回类型泛型中的实参

  2. 接着看adapt这个方法,它会传入Call<R>这个对象,有一个T这个泛型,它是需要我们转换成接口的对象类型;如果对应的是Rxjava的话,那么这个T泛型就是Rxjava中的类型,之后会对RxjavaConvertAdapter进行分析

  3. 接着看Factory这个抽象类,里面有个get方法,它是根据接口返回的注解类型得到实际需要的callAdapter; 关于getParameterUpperBound不用太过关注,它会调用我们的工具类,返回的是我们泛型参数的上限;重要的是getRawType方法,获取我们的原始类型,这和我们判断选择不同的adapter有着直接的联系

    RxjavaCallAdapterFactory实现流程

好了,现在我们来回到RxjavaCallAdapterFactory源码当中,在此之前,我们先来梳理下它的流程

  • 首先实现CallAdapter当中的Factory抽象类,用来提供具体的适配逻辑
  • 将我们的CallAdapter通过add方法添加到Retrofit当中(注册CallAdapter)
  • 调用Factory.get进行获取CallAdapter
  • 最后调用CallAdapter中的adapt方法,用它来转换成每个平台所适用的类型

我们来具体看下代码是怎么实现的

继承Factory
public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
  ....
}
注册CallAdapter

在我们构建Retrofit的时候,调用addCallAdapterFactory就可以注册RxjavaCallAdapterFactory,这里也可以添加自定义的CallAdapter不同平台支持的类型

addCallAdapterFactory(RxJavaCallAdapterFactory.create())
调用Factory.get方法获取CallAdapter

我们回到RxjavaCallAdapterFactory当中,先来看下get方法,代码如下所示

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);
    boolean isSingle = rawType == Single.class;
    boolean isCompletable = rawType == Completable.class;
    if (rawType != Observable.class && !isSingle && !isCompletable) {
      return null;
    }
​
    if (isCompletable) {
      return new RxJavaCallAdapter(Void.class, scheduler, isAsync, false, true, false, true);
    }
      .....
     //最终返回一个RxJavaCallAdapter  进行类型转换     
    return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
        false);
  }

这里基本上这些逻辑都是判断这个rawType是否是Rxjava类型,就不详细赘述了,只要知道最终都会返回RxjavaCallAdapter具体实现对象,然后就调用adapt方法进行最终的call类型转换

adapt请求类型转换

我们先来看下代码,这里是RxjavaCallAdapter中的调用adapt方法

  @Override public Object adapt(Call<R> call) {
    OnSubscribe<Response<R>> callFunc = isAsync
        ? new CallEnqueueOnSubscribe<>(call)
        : new CallExecuteOnSubscribe<>(call);
​
    OnSubscribe<?> func;
    if (isResult) {
      func = new ResultOnSubscribe<>(callFunc);
    } else if (isBody) {
      func = new BodyOnSubscribe<>(callFunc);
    } else {
      func = callFunc;
    }
    Observable<?> observable = Observable.create(func);
​
    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }
​
    if (isSingle) {
      return observable.toSingle();
    }
    if (isCompletable) {
      return observable.toCompletable();
    }
    return observable;
  }

很显然,可以看到,这里就用到Rxjava的知识了,由于方法里涉及到Rxjava中的几个类以及几个变量(IsFlowable,isSingle,isCompletable,isBody,isResult),还是需要了解,不然很有可能看这块代码会一头雾水,可以参考了下面两篇结合官网进行辅助理解

看完之后大概了解了,再回过头来,我们先假设请求的真实类型rawType用的就是Observable,那么isFlowable, isSingle, isMaybe 都是 false的,回到之前的那个获取泛型参数的类型上限,根据源码提供的注释,我们就可以知道就是获取Observable<T>中T的类型上限;一般情况下,这个T类型就是JavaBean,所以isResult为false,isBody为true

知道了这些变量后,然后再看上面的adapt方法

  1. 首先看到isAnsync这个是由RxjavaCallAdapterFactory创建的时候就确定是false了,所以这里会创建一个CallExecuteOnSubscribe对象
  2. 接着根据前面的分析结果,isBody为true,所以得到的是一个BodyOnSubscribe对象
  3. 最后返回这个observable,相对于我们调用接口方法返回就是一个BodySubscribe对象

到目前为止,我们已经了解了,RxjavaCallAdapterFactoryadapt方法就是利用Rxjava中的操作符以及订阅来完成了整个类型适配转换的过程,感兴趣的小伙伴可以继续深入学习这块内容,它具体是如何适配的?由于其中内容过多,就不详细展开了

小结

简单来说,Retrofit中整个网络适配器CallApdater流程,大致如下

  • 我们获取到一个Call对象,拿到这个Call对象去执行http请求,而Retrofit调用这个Call请求,最终调用的还是okhttp里面的Call请求,只不过对其进行了封装,通过这样我们就可以获取到服务器端返回的数据
  • 获取到数据之后我们就会调用converter数据转换器来把我们需要的对象转换出来
  • 具体实现可参考上文RxjavaCallAdapterFactory的阐述