android中Retrofit2源码解析(新版本)

android中Retrofit源码解析(新版)

在android开发中我们原生应用发起网络请求的时候,不免需要使用android对网络请求的封装,它提供了对http协议底层的抽象,我们可以通过它提供的方法直接调用http请求。在android2.2版本及其以前的版本使用HttpClient,在android2.3版本及其之后我们使用了httpUrlConnection,而且在6.0之后android移除了httpClient,我们在高版本的API中只能使用HttpUrlConnection了。

1.1 retrofit和OkHttp的关系

但是实际情况是使用了httpUrlConnection还是很繁琐,我们还是要去考虑超时时间,服务器异常情况、数据流转为实体对象这些烦恼。所以有了对android内置的HttpUrlConnection or httpClient的包装,让我们专心处理业务逻辑。oKHttp就诞生了,android4.4版本以后都内置了oKHttp了,而我们要讨论的retrofit就是再次对okHttp的包装,丰富了很多强大的功能,比如能和Rxjava这个流行的框架结合,返回结果能回调到UI线程等。oKHttp的源码涉及到了对阻塞队列,线程池的应用,我们下一节进行探讨。

1.2 retrofit的本质

retrofit的本质就是应用了大量的设计模式对Okhttp进行了封装,加入了网络数据转换、网络请求回调、网络请求适配这几个主要的功能。它本身肯定不会去发请求的,发请求交给了OkHttp,它只对调用方式和返回结果进行处理其他的不关它的事。为什么要去研究retrofit的源码呢?因为它封装的方式解耦性很高,功能调用十分简洁,可以参照它对我们的代码也能进行改造。

1.3 源码解析(retrofit:2.4.0)

1.3.1 retrofit的创建

一起打开IDE阅读源码更虚浮!retrofit的创建是整个框架的入口,它肯定会提前准备好很多看不懂的变量进行初始化,但是这不能阻挡我们,往后看就能理解它代表的含义了。根据官方的文档,retrofit的创建使用了建造者模式。

Retrofit retrofit = new Retrofit.Builder() 
//基本URL
.baseUrl("https://www.baidu.com") 
//网络请求适配器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
//网络请求数据转换器
.addConverterFactory(GsonConverterFactory.create()) 
//网络请求执行器
.client(new OkHttpClient())       
.build(); 

所谓建造者模式就是有builder关键字的方式,就是这么简单!当然这是一个玩喜,建造者模式和我们以前 get/set 类的属性没有什么本质的区别,主要是将这些set方法全部提取出来 形成一个抽象类或者内部类,然后在一个建造者类里面去设置属性,返回一个实体类对象,列如:

public abstract Builder{
public void BulidProperty(String url);
}
public class RealBuilder extends Builder{
private RealObject object;
public void BulidProperty(String url){
    object.SetProperty(url);
     }
 public RealObject build(){
     return RealObject;
     }
}

简单的思想大概是这样的,具体的我们可以看一下Retrofit中的源码。第一行代码

//第一行代码
Retrofit retrofit = new Retrofit.Builder() 

很明显这个Builder是一个Retrofit的内部类,那说明建造者不是继承了抽象类,而是使用了内部类来设置属性。来看一下这个内部类,如下:


public static final class Builder { 
    //不知道这是什么东东先放在一边
    private final Platform platform;
    //很明显出现了okhttp,就知道它肯定负责去发请求
    private okhttp3.Call.Factory callFactory;  
    // 8必多说 大家都懂
    private HttpUrl baseUrl;
    //很明显它是存数据转换用的,但是为什么搞一个list 懵b?
    private final List<Converter.Factory> converterFactories = new ArrayList<>(); 
    //很明显它存网络适配器用的,再次疑问这个网络适配器是什么东东?
    private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>(); 
    //很明显他是一个回调执行器,这个有什么用呢?
    private Executor callbackExecutor; 
    //这肯定是校验Flag目前不知道有什么用
    private boolean validateEagerly;

里面看不懂的变量主要有adapterFactories存的网络适配器工厂(CallAdapter.Factory),很明显他后面会使用工厂设计模式去产生CallAdapter的对象,至于数据转换器(converter)我们都知道http请求返回来的是数据流InputStream方式的,转为Json,XML之类需要一个转换器,类似于一个double转int的工具类。

  • 网络适配器的含义及其作用:网络适配器是我自己给他的定义,从命名上来看是叫:CallAdapter,Call肯定是来发请求的,Adapter忆往昔峥嵘岁月,在listView里面是界面和数据的桥梁,同理这里的CallAdapter应该是客户端和网络之间桥梁。客户端发请求的操作肯定是要通过它的。如图:
image.png

这样我们就可以清楚的看到了CallAdapter的作用了,它对OkHttp进行包装,我们调用请求方法的时候都要通过它。它同时持有了okHttp对象和回调执行器的对象,这样它通过Okhttp拿到数据之后,用回调执行器回调。

  • 回调执行器:回调执行器就是在拿到数据结果之后,我们怎么返回结果的问题,主要的问题就是由于是异步请求,我们想要使用数据填充界面,需要切换到主线程。
  //再看看构造函数
  Retrofit retrofit = new Retrofit.Builder() 

这个内部类的构造函数做了些什么内容?就一句调用自己的有参构造函数,佛了!

public Builder() {  this(Platform.get());}

我们来看看这个有参构造函数和Platform类是什么东东:

    //Platform类
class Platform {
  private static final Platform PLATFORM = findPlatform();
  static Platform get() {
  //f返回一个实例就完事了
    return PLATFORM;
  }
  //根据不同运行平台返回对应的Platforem对象 
     private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

看到这里我们就明白了,他根据运行的平台不同来返回相应的对象,我们这里只分析 new Adnroid();看看里面有什么内容:

static class Android extends Platform {
 //一个默认的回调执行器
    @Override
     public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    //很明显 很熟悉 !创建了一个默认的CallAdapter(网络适配器),而且传入了一个回调执行器(回调执行器可以自定义,不然就是用默认绑定主线程)
    @Override 
    CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
     static class MainThreadExecutor implements Executor {
     //给力 绑定了主线程的 looper (关于Handler的详细内容可以自己查询)
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override 
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

到此我们明白了 Platfrom的作用了,它提供了一个默认的CallAdapter.Factory用来生产CallAdapter,还提供了一个绑定主线程的默认回调执行器。

再次回头看创建Retrofit的其他代码

Retrofit retrofit = new Retrofit.Builder() 
//基本URL
.baseUrl("https://www.baidu.com")
//可以自定义回调执行器,否则默认回调到主线程
.callbackExecutor("xxxx")
//网络请求适配器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
//网络请求数据转换器
.addConverterFactory(GsonConverterFactory.create()) 
//网络请求执行器
.client(new OkHttpClient())       
.build(); 

baseUrl、add这些方法是给内部类属性赋值,我们主要来看build()方法。

 public Retrofit build() {
    //可见baseUrl 是必须的 使用的时候要注意
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //很明显 生产网络请求的工厂,如果你不传入自定义的okHttp对象,他会默认使用okHttpclient
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //如果没有自定义,加入刚刚说过的默认调到到主线程
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      //将传入到内部类callAdapter copy一份 传入到retrofit的构造函数
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
        //它会添加一个默认的网络适配器,这个网络适配器它持有callbackExecutor回调执行器的对象。
      callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
      //很明显类似adapterFactories 添加了一个默认,再copy一份到 retrofit的构造函数中。
      List<Converter.Factory> converterFactories =new ArrayList<>(1 + this.converterFactories.size());
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      //返回retrofit的实例对象就完事了
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
  }

这里的代码都很简单,但是有几个疑问?为什么这个adapterFactories和converterFactories都是list呢,它里面都存了些什么。

  • adapterFactories: 一个list集合,存储了网络适配器工厂,根据上面的代码我们可以看到它里面的内容是:先添加了自定义的、后面添加了一个默认的,总共两个元素。在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory。其他的没有用过,但是看到Rxjava我们就知道了,如果想要和Rxjava结合起来这个RxJavaCallAdapterFactory必须添加进去
//通过这个添加进去,是不是可以添加多个呢?
Retrofit retrofit = new Retrofit.Builder() 
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//我们还可以添加
// adapterFactories里面顺序
// 自定义1-自定义2-.....默认。
addCallAdapterFactory(Java8CallAdapterFactory.create())
addCallAdapterFactory(GuavaCallAdapterFactory.create())
//converter 同理啊铁子!
.addConverterFactory(GsonConverterFactory.create()) 

也不会有问题,因为我们网络请求都是多种多样的,上面已经说得我们发请求就是操作CallAdapter,所以有结果返回的时候也需要通过CallAdapter。有时候我们需要Rxjava的observeable这种返回对象,有时候我们还是需要Call这种类型的返回对象,所以他需要一个list去组装对应的CalladapterFactory,Call代表了默认CallAapter返回出来的的,Observable代表了我们添加进去的RxJavaCallAdapter返回出来的。同理我们需要从CallAdapter得到想要的数据类型,converterFactories也需要多个。

    @GET
    //我想要Observable 需要相应的的CallAdapter
   Observable<ResponseBody> download(@Url String url);
    @GET
        //我想要Call 默认的CallAdapter就行
        //同时还需要将结果变成IModel 怎么说吧你
    Call<IModel>download(@Url String url);

总结:我们清楚的看到了,retrofit的创建过程,主要的内容就是四个器的初始化,网络适配器(CallAdapter),数据转换器(conver),请求执行器(oKHttp),回调执行器(callbackExecutor)。关注点在我们发请求操作都是CallAdapter,它肯定持有其他三个的引用,就像吃鸡里面他是我们的角色,其他的是M4,头盔 药品等。

1.3.2 创建网络请求接口的实例。

对我们的的注解定义的接口方法进行解析,从而创建实例,有点迷惑?什么实例,干什么用的?我们继续往下看。

retrofit.create(RetrofitService.class);

看到这种传入.class的 ,我们可以想到肯定会用到反射。

 public <T> T create(final Class<T> service) {
    //校验接口正确性,是否符合注解规则
    Utils.validateServiceInterface(service);
    //validateEagerly 这个变量主要是作用是 是否提前加入缓存
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //很明显这里使用了动态代理模式
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
              //如果是java里面的基类不做处理 
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            // 这个没什么用android平台默认返回的是false的
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
           //非常重要的3行代码
           //解析方法的返回参数 请求参数 请求类型等
            ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
            //很明显OkHttp就知道他是一个网络执行器
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //很明显他 肯定是调用了callAdapter  
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

这里的代码稍微有一丢丢复杂,主要理解代理模式。代理代理,不知道大家是否知道代购。比如你想买一件surpene的衣服,当然superme肯定买不起,只能买买faker。又拉下不脸,找了一个代购。

image.png

代理类会获取被代理类的所有方法,并返回一个被代理类的对象,这个对象就是虚拟的你,通过它去购买需要的商品。Proxy.newProxyInstance(xxx)是固定用法,只要传入xxx.class参数就行。

     //固定格式
     ClassLoader classLoader =Shop.class.getClassLoader();
     //固定格式,三个参数,传入Shop.class参数,获取所有方法,返回代理对象。
     Shop shopProy = (Shop) Proxy.newProxyInstance(classLoader, new Class[]{IShop.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //回调原来类的方法,该怎么做就怎么做
                Object result = method.invoke(proxy,args);
                //也可以自己实现 不回调原来的方法。
                //.............................
                return result;
            }
        });

这里的Invoke方法,就是代理方法的实现,method.invoke()代表了回调原来的方法,这里也可以自己去实现方法,只要返回对应的类型。代理模式优点就是提供了一个拦截接口,不管你什么方法调用都会先进入Invoke。具体内容可以学习JAVA反射来加深印象。

  .........................................
  //validateEagerly 这个变量主要是作用是 是否提前加入缓存
   if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //很明显这里使用了动态代理模式
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
              //.............................
           //非常重要的3行代码
           //解析方法的返回参数 请求参数 请求类型等 关键代码1
            ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
            //很明显OkHttp就知道他是一个网络执行器 关键代码2
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //很明显他 肯定是调用了callAdapter   关键代码3
            return serviceMethod.adapt(okHttpCall);
            }

回到代理创建接口实例的方法中,我们创建接口的时候都是只写了方法名,没有具体的实现,所以在代理对象并不能回调,它只能自己去实现而且还要返回你要想的结果类型。苦b啊!

public interface RetrofitService {
  //没有方法体 只有名字 怎么破(只能靠retrofit给我们实行)
   @GET
  Observable<ResponseBody> download(@Url String url);
   // 没有方法体,只有名字 怎么破
   @GET
   Call<ResponseBody>download(@Url String url);
}

在retrofi中,利用了ServceMehod这个类来进行实现方法体,它会获取到接口方法的参数,返回值类型,请求方式等所有参数。看一下关键代码1,loadServiceMethod()!!

 ServiceMethod<?, ?> loadServiceMethod(Method method) {
   //搞个缓存啊 美滋滋
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
      //缓存里面没有,说明是第一次调用,安排一下,并且加入缓存
        result = new ServiceMethod.Builder<>(this, method).build();//我只是一个建造者,传入了retrofit的对象,拥有了adapterFactorese等所有属性。
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

代码很简单,对调用的方法做一个缓存,第一次调用的时候才会去解析方法,其他情况下会使用缓存。同时我们也应该知道validateEagerly这个Flag的作用了,如果你设置为true会创建动态代理对象的时候将所有的方法解析缓存,否则就只会在第一次调用的时候去缓存。
虽然已经知道了ServiceMethod会对我们请求的方法进行一顿瞎x操作,各种解析分析组装,但是我们还要要去看看实况,它采用了建造者模式(builder),直接看.build()方法。

 public ServiceMethod build() {
     ..........................................//
     //根据返回值类型,在adapterFactories的list里面去寻找CallAdapter,如observeable,就会寻找RxjavCallAdapter.Factory 工厂模式产生CallAdapter 的对象。
      callAdapter = createCallAdapter();
      //获取返回值中的数据类型
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      //根据CallAdapter的返回的值中的数据类型(如: Call<Bean> download(), 就会根据 ‘ Bean’去寻找Gson转换器)去遍历converterList找转换器,Converter 的对象。
      responseConverter = createResponseConverter();
      //遍历方法中的所有注解 一顿操作保存起来。
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      int parameterCount = parameterAnnotationsArray.length;
      // 保存请求参数的工具类
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        ..................///
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        ..................//
        //遍历方法参数中的所有注解和变量到parameterHandlers
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      .......................//
      //返回一个 ServiceMethod的实例
      return new ServiceMethod<>(this);
    }

主要作用是根据方法的返回值类型,获取相应的网络适配器、数据转换器以及拆卸参数类型等保存在parameterHandlers中。列如:createCallAdapter会去遍历callAdapterFactories找到相应的callAdapter。

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
      //.......................................................
      //根据返回值遍历callAdapterFactories
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
     // get返回了一个CallAdapter对象
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    
    //这里假设我们返回值是 Call<Bean> 类型的 ,默认的ExecutorCallAdapterFactory会被匹配到。看看它的get方法
  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    //给力呀 铁子 返回了一个 CallAdapter对象
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }
      // 我就是方法体啊铁子 
      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

其中Calladapter中的adapt方法就是方法体了。后续详细介绍这个CallAdapter类。
根据关键代码1, loadServiceMethod()返回了一个ServiceMethod的实例,它里面包含了你调用方法的所有信息,包含注解,参数类型,参数名,返回值类型等,来看看它里面主要的属性:

  final class ServiceMethod<R, T> {
   .............................//
  //这个是Okhttp的工厂实例,用来生产请求call的
  private final okhttp3.Call.Factory callFactory;
  //桥梁callAdapter 实例 发请求都是它在操作okhttp
  private final CallAdapter<R, T> callAdapter;
  // 8 必再说
  private final HttpUrl baseUrl;
  //数据转换器实例
  private final Converter<ResponseBody, R> responseConverter;
.......................//
//存储请求参数的集合
  private final ParameterHandler<?>[] parameterHandlers;

到此Retrofi已经实现了高度的解耦,定义一个请求方法,我只想调用一下得到结果,至于怎么请求的,和怎么转换结果都不想关注。retrofit在这里使用了外观模式,只用定义方法入口(Retrofit.create(YourInterface.Class)),减少了对内部细节的依赖,里面发生了变化,我们也不用担心。
继续看关键代码2:

//很明显这里使用了动态代理模式
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
              //.............................
           //非常重要的3行代码
           //解析方法的返回参数 请求参数 请求类型等 关键代码1
            ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
            //很明显OkHttp就知道他是一个网络执行器 关键代码2
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //很明显他 肯定是调用了callAdapter   关键代码3
            return serviceMethod.adapt(okHttpCall);
            }

将servcieMethod传入到oKhttpCall,serviceMethod已经把请求参数拆卸下来存储在了parameterHandlers中,OkHttpCall会取出参数类型和值进行组装请求。

final class OkHttpCall<T> implements Call<T> {
  private final ServiceMethod<T, ?> serviceMethod;//含有所有网络请求参数类型等等
  private final @Nullable Object[] args;//请求参数的值

  private volatile boolean canceled;//取消请求Falg

  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;//真正发请求的Okhttp
............................................//

  }

OkHttpCall里面有了okhttp对象,使用它来进行发请求操作,具体我们往下看。
关键代码3:

        //很明显他 肯定是调用了callAdapter   关键代码3
            return serviceMethod.adapt(okHttpCall);
    // 在ServiceMethod中adapt 调用了callAdapter
    final class ServiceMethod {
    ..................................//
      T adapt(Call<R> call) {
          return callAdapter.adapt(call);
        }
   ...............................//     
     }      

将生产好的Call对象传入到adapter中,然后开始实现方法体.
这里结合实例来看:

    //我想要Call类型的返回值,使用默认CallAdapter的就行了
    @GET
    Call<Model>download(@Url String url);
    
    //使用 mRetrofitService.downloadADfile(xxx),就是在调用  serviceMethod.adapt(okHttpCall);
    Call<Model> call = mRetrofitService.downloadADfile("www.kawayi.com");   

我们在这里的 "call = "返回的是什么呢?来看一哈肯定很简单。

//根据刚返回类型'Call' 遍历CallAdapterFactories循环出得到默认CallAdapter
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }
      //返回了一个ExecutorCallbackCall对象 来看一哈
      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

很显然返回了一个ExecutorCallbackCall对象,ExecutorCallbackCall内容并不是很复杂。

//这里是ExecutorCallbackCall 继承了Call
static final class ExecutorCallbackCall<T> implements Call<T> {
  //回调执行器,有自定义就用自定义否则就会使用platform这个对象生产出绑定主线程的回调
  final Executor callbackExecutor;
  //这里传入的是OkhttpCall
  final Call<T> delegate;
  //构造函数,传入了OkhttpCall,和回调执行器,装饰模式安排安排
  ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
    this.callbackExecutor = callbackExecutor;
    this.delegate = delegate;
  }
  //执行异步请求
  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");
    delegate.enqueue(new Callback<T>() {
      @Override public void onResponse(Call<T> call, final Response<T> response) {
          //回调执行器 切换线程
        callbackExecutor.execute(new Runnable() {
          @Override public void run() {
            if (delegate.isCanceled()) {
              callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
            } else {
              callback.onResponse(ExecutorCallbackCall.this, response);
            }
          }
        });
      }
     .......................//
}

代码很简单,显然CallAdapter的内部类ExecutorCallbackCall拥有okhttp和回调执行器,所有的一切操作都在是它在执行了。这里使用了装饰模式,加强了okhttCall。装饰模式:就是不改变类文件和使用继承的情况下,动态地扩展一个对象的功能,是一种代替继承的方案。


image.png

C和A都继承了B,但C里面有A的对象,所以他可以调用A的方法,而且能添加一些A中没有的功能。如:

  
  static final class ExecutorCallbackCall<T> implements Call<T> {
   ......................................//
    //ExeCutorCallbackCall和delegate都继承了Call,但ExeCutorCallbackCall有回调执行,取消请求这些功能,得到了加强。
    final Call<T> delegate;

这里的delegate得到了加强,拥有了切换线程的功能。

总结:retrofit.create(RetrofitService.class),使用了动态代理创建RetrofitService对象,并且对它接口中的方法进行了实现,根据返回值的类型,寻找CallAdapter和converter并且拆卸请求参数,组装请求,最后返回了Call的对象。

1.3.3 返回值执行网络请求

根据实例来看源码:


//我想要Call类型的返回值,使用默认CallAdapter的就行了 
@GET Call<Model>download(@Url String url); 
//实际上就是在调用serviceMethod.adapt(okHttpCall); 
Call<Model> call = mRetrofitService.downloadADfile("www.kawayi.com");
//发一个异步请求。
 call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

            }
            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
            }
   });

根据刚刚分析的代码可以知道,返回的call对象是ExecutorCallbackCall的实例,enque执行异步请求的,就会调用ExecutorCallbackCall的enque方法。

//这里是ExecutorCallbackCall 继承了Call
static final class ExecutorCallbackCall<T> implements Call<T> {
  //执行异步请求
  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");
    //okhttpCall去执行请求,奥给力。
    delegate.enqueue(new Callback<T>() {
      @Override public void onResponse(Call<T> call, final Response<T> response) { 
      //这只是一个回调执行器,切换线程
        callbackExecutor.execute(new Runnable() {
          @Override public void run() {
            if (delegate.isCanceled()) {
              callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
            } else {
              callback.onResponse(ExecutorCallbackCall.this, response);
            }
          }
        });
      }
     .......................//
}

代码中可以看到,我们传入的okHttpCall(serviceMethod.adapt(okHttpCall))会调用okttp去执行请求,并且用回调执行器回调okhttp返回的数据数据。
下面来看看okHttp具体是怎么处理的

 final class OkHttpCall<T> implements Call<T> {
  private final ServiceMethod<T, ?> serviceMethod;//含有所有网络请求参数类型等等
  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;//真正发请求的Okhttp
............................................//
  //发一个异步请求。实际上是okhttp操作
 @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");
    //okhttp的实例
    okhttp3.Call call;
    ..............................................\\
   call = rawCall = createRawCall() ;//拿到parameterHandlers的参数,组装一个请求   
   ...........................................\\
   //真正的发一个请求
  call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
        //使用数据转换器,转换一下就完事了。
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
         try {
         //回到到对应的CallbackCall中,默认是ExecutorCallbackCall
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
        
        

OkhttpCall首先先对请求进行一个组装,然后赋值给一个okhttp.Call的对象。通过call对象去发起请求,中间有异常超时对应的处理,拿到正确的请求结果之后,解析数据,回调到对应的CallbackCall,默认是ExecutorCallbackCall,最后在ExecutorCallbackCall中使用回调执行器再次回调。

2.1 总结

1、Retrofit对oKHttp层层封装,利用动态代理模式,实现接口定义的方法。
2、根据返回值类型匹配对应的CallAdapter,converter,这里使用了策略模式。在对应的callAdapter中使用了装饰器模式并且返回了一个加强的Call对象。
3、利用返回的Call对象来发请求,利用内部包装的OkHttp对象,执行请求。结果返回之后,converter解析数据,经过层层回调,到最后回调执行器切换线程。

参考文献
[1]刘望舒.Android进阶之光

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容