您当前的位置: 首页 > 

郭梧悠

暂无认证

  • 2浏览

    0关注

    402博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Retrofit之CallAdapter简单解析

郭梧悠 发布时间:2018-09-10 22:01:03 ,浏览量:2

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

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

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

/*执行同步请求*/
Resonse 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 完成api.getData()的执行。 其invoke方法如下所示:

//Retrofit的create方法(删除了部分与本文无关的代码)
public  T create(final Class 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 serviceMethod =
                (ServiceMethod) loadServiceMethod(method);
            
              //创建OkHttpCall对象    
            OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
           
            //返回ExecutorCallbackCall
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }//end create

//ServiceMethod的adapt方法:
T adapt(Call 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 serviceMethod =
             loadServiceMethod(method);
             
   //直接返回OkHttpCall
    return new OkHttpCall(serviceMethod, args);
}

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

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

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

interface MyApi {
   Call loadA();
   Call loadB();
   Call loadC();
}

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

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

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

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

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

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

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

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


interface MyApi {
   Call loadA();
   Call loadB();
   Call loadC();
   MyDefineType 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 serviceMethod =
                (ServiceMethod) loadServiceMethod(method);
            
              //创建OkHttpCall对象    
            OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
           
            //返回ExecutorCallbackCall
            return serviceMethod.adapt(okHttpCall);
          }

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

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

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

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

  final List callAdapterFactories;

这个集合不是List的集合,而是其工厂的对象的集合。工厂对象的目的就是用来创建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 callAdapterFactories = new ArrayList();
   public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      adapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

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

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

      //添加callAdapter的工厂对象
      List 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 createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      
       //省略部分代码
      Annotation[] annotations = method.getAnnotations();
      
        return (CallAdapter) 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类型
   
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    //获取Call的真实类型T
    final Type responseType = Utils.getCallResponseType(returnType);
   
    return new CallAdapter            
关注
打赏
1663674776
查看更多评论
0.0484s