美文网首页
Android开源框架-Retrofit源码解析(一)

Android开源框架-Retrofit源码解析(一)

作者: 安安_660c | 来源:发表于2022-05-07 15:34 被阅读0次

    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的源码

    未完待续

    相关文章

      网友评论

          本文标题:Android开源框架-Retrofit源码解析(一)

          本文链接:https://www.haomeiwen.com/subject/sjlxurtx.html