Retrofit之CallAdapter简单解析

阅读本篇博客之前,建议读者先按顺序读一读博主的下面几篇博客:
Retrofit源码解析之请求流程概述
Retrofit之Converter简单解析
Retrofit之OkhttpCall执行原理详解
根据前几篇博客我们知道,Retrofit常规使用方法可以用如下几行代码表示:

MyApi api = retrofit.create(MyApi.class);

/*获取ExecutorCallbackCall*/
Call<T> call= api.getData();

/*执行同步请求*/
Resonse<T> response = call.execute();

/*获取真实数据*/
T data = response.body();

上述代码中的call对象的实例为ExecutorCallbackCall(常规使用情况,没考虑跟Rx结合的情况),它的主要作用就是代理了OkhttpCall执行网络execute/enqueue(同步/异步)请求,同时将异步的回调通过Handler转接到Android主线程调度队列里面。(详见 Retrofit源码解析之请求流程概述).

同时上述代码api.getData()的执行是通过代理对象的invoke方法执行的,主要做了三个工作:
1、将getData()方法的Method对象,及其方法注解,方法参数,方法参数注解等信息封装成一个ServiceMethod对象。
2、根据骤1生成的ServiceMethod对象,创建一个OkhttpCall对象
3、调用callAdapter.adpte(okhttpCal)方法返回Call<T> 完成api.getData()的执行。
其invoke方法如下所示:

//Retrofit的create方法(删除了部分与本文无关的代码)
public <T> T create(final Class<T> service) {
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
   
          @Override 
          public Object invoke(Object proxy, Method method, @Nullable Object[] args)
            //创建SeriviceMethd对象
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            
              //创建OkHttpCall对象    
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
           
            //返回ExecutorCallbackCall
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }//end create

//ServiceMethod的adapt方法:
T adapt(Call<R> call) {
    return callAdapter.adapt(call);
  }

问题来了,既然ExecutorCallbackCall只是OKHttpCall的一个代理类,比如该类的execute()方法内部t就是直接调用了OKHttpCall的execute方法而已。那么为什么还要这个callAdapter呢?完全可以将invoke方法改成如下所示:

//修改后的invoke方法
public Object invoke(Object proxy, Method method, @Nullable Object[] args){
    //创建ServiceMethod       
    ServiceMethod<Object, Object> serviceMethod =
             loadServiceMethod(method);
             
   //直接返回OkHttpCall
    return new OkHttpCall<>(serviceMethod, args);
}

改动后的代码在执行api.getData()后返回的Call<T>就是OKhttpCall了,同样我们也可以拿到正确的数据.那么我们可以设想一下为什么Retrofit还要设计一个CallAdapter接口呢?

回答这个问题之前,先来说一个客观事实,Retrofit真正使用Okhttp进行网络请求的就是OkHttpCall这个类。上面改动后的invoke方法确实能满足要求,因为返回的就是OkHttpCall这个对象,直接操控这个对象就可以完成网络请求。

但是改动后的代码带来的后果之一就是:因为OkHttpCall实现了Call接口,API Service方法的返回值必须是Call<T>类型,直观表现如下所示:

interface MyApi {
   Call<ABean> loadA();
   Call<BBean> loadB();
   Call<CBean> loadC();
}

那么如果我们想要返回的不是Call呢?比如RxJava的Observable,这种情况下该 怎么办呢?
适配器模式在此发挥了其应用的作用!!!

将网络请求的核心类OkHttpCall进行适配,你需要什么类型的数据就通过适配器适配,返回适配后的对象就是了。Retrofit适配器的接口设计如下:

//R原始类型,T适配后的类型
public interface CallAdapter<R, T> {
  //泛型包裹的真实对象类型,比如Call<A>则就是A的Type对象
  Type responseType();

  //Returns an instance of {@code T} which delegates to {@code call}.
  //返回一个T类型来代理Call,在这里可以先认为是OkHttpCall
  T adapt(Call<R> call);
}

这么一来,我们的API方法的返回类型就不再仅仅限制于Call这个类型了,比如你想返回的是一个自定义类型,该类型暂且命名为MyDefineType,那么就可以简单的这么做:

//自定义适配器
class MyCallAdapter implement CallAdapter {
   
   
   public <R> MyDefineType<R> adapt(Call<R> call) {
      
      return new MyDefineType(call);
    }
}

class MyDefineType<R> {
  //代理OkHttpCall
  private final Call<R> delegate;
  
  MyDefineType(Call<R> call){
      this.delegate = call;
   }
  
  public R execute() {
     Reponse<R> response = delegate.execute();
     return response.body();
  }
}

有了上面的Call适配器之后,我们就可以扩展我们API:


interface MyApi {
   Call<ABean> loadA();
   Call<BBean> loadB();
   Call<CBean> loadC();
   MyDefineType<DBean> loadD();
}

此时loadD的调用直接就是:

DBean data = myApi.loadD().execute();

正式这种CallApdate接口的设计,使得我们在使用Retrofit的时候可以自定义我们想要的返回类型。此接口的设计也为RxJava的扩展使用做了很好的基础!!!

从上面的讨论可以得出如下结论:每个Api方法的返回类型都需要一个CallAdapter对象与之对应。可以用下图来表示:

这里写图片描述

再结合OkhttpCall和前面几篇文章讲解的Converter的话,上面的图示就可以扩展为如下所示:
这里写图片描述

其实通过上图以及Retrofit代理类的invoke方法可以看出一个问题,问题就是Retrofit硬编码的方式强制使用了OkhttpCall(注意OkhttpCall实现了Call接口),而没有用Call接口的自定义实现类:

 public Object invoke(Object proxy, Method method, @Nullable Object[] args)
            //创建SeriviceMethd对象
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            
              //创建OkHttpCall对象    
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
           
            //返回ExecutorCallbackCall
            return serviceMethod.adapt(okHttpCall);
          }

如果考虑到扩展性的话,上面初始化OkhttpCall的代码的代码应该这么写:

   //通过工厂对象类获取Call
   Call<Object> call = callFactory.createCall(params);

通过工厂的形式获取Call接口的实例,而不是直接硬编码,这样就可以带来很好的扩展性.其实Retrofit设计Call的初衷应该就是为了这个扩展。但是目前好像还没有很好的实现,可能后期会有所表示吧。那么理论上的Retrofit可能就会变成如下所示了:
这里写图片描述
那么如何判定选取哪个CallAdapter来工作呢?Retrofit是怎么检索出需要哪一个CallAdapter的,下面就来仔细分析这个问题:


说道CallAdapter检索,顾名思义,就是需要从一堆共性的东西里查找某一个合适的对象。在Retrofit中就有CallAdapter的集合:

  final List<CallAdapter.Factory> callAdapterFactories;

这个集合不是List<CallAdapter>的集合,而是其工厂的对象的集合。工厂对象的目的就是用来创建CallAdapter对象的,且根据上文我们知道每个Api方法的返回类型都需要一个CallAdapter对象与之对应,对这句话进行需求分析来看就是根据返回类型返回一个CallAdapter对象。伪代码用如下:

   if(returnType == A){
       return CallAdapterA();
   }else if(returnType == B){
       return CallAdapterB()
   }else if(returnType==C) {
      return CallAdapterC();
   }else if(...){
      ...
   }else{
     return DefaultCallAdapter();
   }

这种代码看着就很蛋疼,所以此时工厂模式起到了很好的作用。该CallAdapter.Factory代码主要代码如下:

abstract class Factory {

   //根据returnType等信息返回一个与之对应的CallAdaper
    public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
        Retrofit retrofit);
  }

既然Retrofit提供了callAdapterFactories,其在Retrofit.Buider里的构建过程在此也简单的了解一下,具体的添加Factory的代码在Builder中如下所示:

  private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
   public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      adapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

那么Builder在构建Retrofit对象的时候就如下所示了:

   public Retrofit build() {
       //省略部分代码

      //添加callAdapter的工厂对象
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  
      //添加一个默认的CallAdapter:博文后面会有说明
      callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

     //省略部分代码
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);

    }

代码分析到现在,CallAdapter的工厂对象都放到了一个List集合里面,剩下的就是怎么从这个集合里检索出所对应的CallAdater了。

根据之前博客的分析,我们知道在执行一个api方法的时候都会构建一个ServcieMethod对象,该对象表示一个api方法的封装,同时该对象有个createCallAdapter方法,该方法的主要作用就是根据对应api方法的返回值来从上述集合中获取一个合适的CallAdapter:

    private CallAdapter<T, R> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      
       //省略部分代码
      Annotation[] annotations = method.getAnnotations();
      
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
 
    }

注意createCallAdapter方法的调用实在ServiceMethod.Builder的buid方法中完成的:

  public ServiceMethod build() {
      callAdapter = createCallAdapter();
  }

最终会调用retrofit的callAdapter对象:

  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }


  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
      
    int start = callAdapterFactories.indexOf(skipPast) + 1;
     //遍历工厂类集合,返回符合要求的一个CallAdapter
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {//不等于null
        return adapter;
      }
    }

  }

很简单,只是简单的做了集合遍历的操作,然后返回符合标准的CallAdapter.

所以Retrofit的简单流程可以如下所示:
在这里插入图片描述


文章开头说过默认的CallAdapter返回的Call是ExecutorCallbackCall,那么这个Call对象是怎么生成的?在构建Retrofit的CallAdapter.Factory的时候,Retrofit.Builder有这么一段代码:

  callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor))

而platform对象的defaultCallAdapterFactory返回的就是ExecutorCallAdapterFactory:

 CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    //此处不为null
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
  }

而ExecutorCallAdapterFactory工厂对象返回的CallAdapter对象如下:

public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //Api方法的返回值必须是Call<T>类型
   
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    //获取Call<T>的真实类型T
    final Type responseType = Utils.getCallResponseType(returnType);
   
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
       //最终返回的是ExecutorCallbackCall
       //注意adapt方法参数的call是OkhttpCall
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

该Adapter主要做了三件事:
1、判断某Api方法的返回类型是否是Call<T>类型,如果不是则返回null,也就是如下代码所示:

interface Api{
  Call<T> getData(map)
}

也就是说凡是返回Call类型的api方法,其CallAdapter对象对应的就是ExecutorCallAdapterFactory返回的CallAdapter对象.
2、拿到Call<T>泛型的真实类型,然后交给CallAdapter
3、最终Api的getData方法返回的Call就是ExecutorCallbackCall。

Api api = retrofit.create(Api.class)
//ExecutorCallbackCall
Call<T> call= api.getData(map);

//获取真实数据
T data = call.execute().body();

到此位置,本篇博文就此结束,如有不当之处欢迎批评指正

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付 19.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值