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

315 阅读5分钟

Retrofit作为主流的网络请求框架,内部封装OkHttp发起请求,也是声明式Http客户端,使用接口 + 注解的方式在接口中编写请求方法,前文铺垫了这么多,接下来我们就正式进入Retrofit的源码之旅

网络通信流程8步骤&7个关键成员变量

在解析retrofit的源码之前,先回顾下retrofit网络通信的八步骤,有一个宏观的认知

网络通信8步
  • 创建retrofit实例
  • 定义一个网络请求接口并为接口中的方法添加注解
  • 通过动态代理生成网络请求对象,也就是解析网络请求接口中的注解
  • 通过网络请求适配器将网络请求对象进行平台适配(包括Android,Java8,IOS等的)
  • 通过网络请求执行器发送网络请求
  • 通过数据转换器解析数据
  • 通过回调执行器切换线程
  • 用户在主线程处理返回结果

以上就是Retrofit进行网络通信的步骤,大致代码如下所示,相信之前大家已经耳熟能详了

 val retrofit = Retrofit.Builder()
            .baseUrl("https://www.baidu.com") //请求url地址
            .addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //设置Rxjava
            .build()
        val myInterface = retrofit.create(MyInterface::class.java)
​
        val call = myInterface.getCall()
        call.execute()
​
        call.enqueue(object : Callback<List<MyResponse>>{
            override fun onResponse(
                call: Call<List<MyResponse>>,
                response: Response<List<MyResponse>>
            ) {
​
            }
​
            override fun onFailure(call: Call<List<MyResponse>>, t: Throwable) {
​
            }
​
        })
7个关键成员变量

接下来我们开始看下Retrofit的源码,首先就可以看到它创建了7个变量,先来搞清楚这些成员变量的作用,对之后理解Retrofit通过动态解析挺有帮助的

  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
  final okhttp3.Call.Factory callFactory;
  final HttpUrl baseUrl;
  final List<Converter.Factory> converterFactories;
  final List<CallAdapter.Factory> callAdapterFactories;
  final @Nullable Executor callbackExecutor;
  final boolean validateEagerly;
serviceMethodCache
  • 它是一个Map对象,这里是ConcurrentHashMap对象,看下它的key值method,也就是http请求的方法,value值是ServiceMethod,看到这里有点懵,查阅资料后才知道它代表网络请求接口中对方法进行解析,然后解析之后的对象就是ServiceMethod,相当于和注解中的@Get,@Post是成对出现的,一一对应;
  • 它的作用主要是用于缓存,比如说存储网络请求的配置,还有网络请求的方法,数据转换器,网络请求适配器等等
callFactory
  • 它是请求网络OkHttp的工厂,由于retrofit默认的工厂就是OkhttpClient,这个在之前解析Okhttp的时候已经详细提过了,这里就不赘述了,这个工厂的作用就是用于生成我们的OkhttpClient
baseUrl
  • 这个很简单了,就是网络请求基础地址url,有了基地址,那就有相对地址,在接口当中的相对地址拼接起来就是个完整的url地址
List<Converter.Factory>,List<CallAdapter.Factory>
  • 这两个都是集合,前者是数据转换器工厂的集合,数 据转换器就是对我们请求之后得到的response进行的转换成能用java对象,总的来说它是用于放置数据转换器的工厂;后者是网络请求适配器工厂的集合,把Call对象转换成其他类型,比如说平台想支持Rxjava的话,就可以转换成Rxjava的Call对象,就是用于生产CallAdapter,这里简单说下,后期需要详细说明
Executor
  • 这是用于执行回调的,在Android平台当中,会看到Platform这个变量在Retrofit的Builder内部类中,默认使用MainThreadExecutor主线程池;其实我们只要明白,在Retrofit中的网络请求最终都是通过线程池将handler进行调配的,可以处理主线程与子线程的切换;在处理异步的网络请求时就需要它了
validateEagerly
  • Boolean类型,这是个标志位,表示的是是否立即解析接口中的方法

Retrofit的Builder内部类

  1. Retrofit是通过建造者模式构建出来的,我们首先看它的Builder内部类,是一个静态内部类
public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private @Nullable HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;
​
    Builder(Platform platform) {
      this.platform = platform;
    }
​
    public Builder() {
      this(Platform.get());
    }
    ....
  • 可以看下几个成员变量,Platform表示Retrofit适配的平台,默认情况都是使用Android平台;callFactory表示的是请求网络Okhttp的工厂,默认情况下就是OkhttpClient; baseUrl表示网络请求url地址,需要注意的是这里是HttpUrl,所以需要把String类型的url转换为HttpUrl类型才能够被Retrofit使用;convertFactories表示数据转换器工厂的集合;adapterFactories表示网络适配工厂的集合;callbackExecutor表示执行异步回调的;validateEagerly表示是否需要立即解析接口中的方法,这个标志位用在动态代理要解析定义的注解和方法中,会进行判断;
  • 回顾这些成员变量和前面介绍地7个成员变量大体基本是类似地,除了PlatForm是Retrofit所没有的,所以说我们也能看出构建者模式就是通过Builder这个内部类进行配置,通过这个配置就能把Retrofit当中的成员变量初始化
  1. 接下来我们查看下Builder类的无参构造方法
    public Builder() {
      this(Platform.get());
    }

传入的是Platform.get(),返回的就是适配平台,我们可以继续看下Platorm内部做了什么

 private static final Platform PLATFORM = findPlatform();
​
  static Platform get() {
    return PLATFORM;
  }
​
  private static Platform findPlatform() {
    return "Dalvik".equals(System.getProperty("java.vm.name"))
        ? new Android() 
        : new Platform(true);
  }
​
  private final boolean hasJava8Types;
  private final @Nullable Constructor<Lookup> lookupConstructor;
​
  Platform(boolean hasJava8Types) {
    this.hasJava8Types = hasJava8Types;
​
    Constructor<Lookup> lookupConstructor = null;
    if (hasJava8Types) {
      try {
        lookupConstructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
        lookupConstructor.setAccessible(true);
      } catch (NoClassDefFoundError ignored) {
      } catch (NoSuchMethodException ignored) {
      }
    }
    this.lookupConstructor = lookupConstructor;

可以看到Platform其实就是个单例,它的get方法最终都是调用findPlatform方法,根据不同的运行平台来提供不同的线程池;我们看下findPlatform方法中做了什么操作,它其实就是返回虚拟器所在的那个平台,默认是在Android平台

我们看下这个Android类的代码

class Android extends Platform {
    ....
    @Override
    public Executor defaultCallbackExecutor() {
       
      return new MainThreadExecutor();
    }  
    
    
    
    static final class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
 
      @Override
      public void execute(Runnable r) {
        //通过handler post到主线程
        handler.post(r);
      }
    }
  • 它这里会返回一个默认的回调执行器defaultCallbackExecutor,见名知义,简单来说,这个执行器的作用就是用于切换线程,同时在主线程中执行回调方法
  • 它会返回一个MainThreadExecutor(),这个在下面已经初始化好了,内部有个Handler调用的是Looper.getMainLooper()这个静态方法,这个Executor已经和主线程(UI线程)绑定了,为了把返回值的处理切换到UI线程, 所以说这也是它能够在主线程回调方法的原因
  1. 我们回到Builder内部类当中,接下来我们看下Builder的有参构造方法
    Builder(Platform platform) {
      this.platform = platform;
    }
    ...

这里很简单,看到就是将平台对象进行赋值给Builder内部类的成员变量platform,对于Builder我们日常使用中通常使用空参这个this(Platform.get())设置retrofit使用平台

以上就是对Builder的简单分析, 总结以下,它主要是做了以下工作

  • 配置平台类型的对象Platform,默认使用Android
  • 配置了网络适配和数据转换的工厂
  • Executor执行异步回调,这里只是默认值的初始化,还没有真正部署到Retrofit的成员变量中

总结

这部分主要介绍了Retrofit的builder构建者模式以及builder内部类的成员变量的作用,接下来会继续学习分析Retrofit的源码

未完待续