【一起學習Android開源框架】Retrofit原始碼解析-1(第四部分)

語言: CN / TW / HK

highlight: androidstudio theme: vue-pro


Retrofit作為主流的網路請求框架,內部封裝OkHttp發起請求,也是宣告式Http客戶端,使用介面 + 註解的方式在介面中編寫請求方法,前文鋪墊了這麼多,接下來我們就正式進入Retrofit的原始碼之旅

網路通訊流程8步驟&7個關鍵成員變數

在解析retrofit的原始碼之前,先回顧下retrofit網路通訊的八步驟,有一個巨集觀的認知

網路通訊8步
  • 建立retrofit例項
  • 定義一個網路請求介面併為介面中的方法添加註解
  • 通過動態代理生成網路請求物件,也就是解析網路請求介面中的註解
  • 通過網路請求介面卡將網路請求物件進行平臺適配(包括Android,Java8,IOS等的)
  • 通過網路請求執行器傳送網路請求
  • 通過資料轉換器解析資料
  • 通過回撥執行器切換執行緒
  • 使用者在主執行緒處理返回結果

以上就是Retrofit進行網路通訊的步驟,大致程式碼如下所示,相信之前大家已經耳熟能詳了

java val retrofit = Retrofit.Builder()           .baseUrl("http://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通過動態解析挺有幫助的

java  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,List
  • 這兩個都是集合,前者是資料轉換器工廠的集合,數 據轉換器就是對我們請求之後得到的response進行的轉換成能用java物件,總的來說它是用於放置資料轉換器的工廠;後者是網路請求介面卡工廠的集合,把Call物件轉換成其他型別,比如說平臺想支援Rxjava的話,就可以轉換成Rxjava的Call物件,就是用於生產CallAdapter,這裡簡單說下,後期需要詳細說明
Executor
  • 這是用於執行回撥的,在Android平臺當中,會看到Platform這個變數在Retrofit的Builder內部類中,預設使用MainThreadExecutor主執行緒池;其實我們只要明白,在Retrofit中的網路請求最終都是通過執行緒池將handler進行調配的,可以處理主執行緒與子執行緒的切換;在處理非同步的網路請求時就需要它了
validateEagerly
  • Boolean型別,這是個標誌位,表示的是是否立即解析介面中的方法

Retrofit的Builder內部類

  1. Retrofit是通過建造者模式構建出來的,我們首先看它的Builder內部類,是一個靜態內部類

java 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當中的成員變數初始化

  • 接下來我們檢視下Builder類的無參構造方法

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

傳入的是Platform.get(),返回的就是適配平臺,我們可以繼續看下Platorm內部做了什麼

java 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類的程式碼

```java 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執行緒, 所以說這也是它能夠在主執行緒回撥方法的原因

  • 我們回到Builder內部類當中,接下來我們看下Builder的有參構造方法

java    Builder(Platform platform) {      this.platform = platform;   }   ...

這裡很簡單,看到就是將平臺物件進行賦值給Builder內部類的成員變數platform,對於Builder我們日常使用中通常使用空參這個this(Platform.get())設定retrofit使用平臺

以上就是對Builder的簡單分析, 總結以下,它主要是做了以下工作

  • 配置平臺型別的物件Platform,預設使用Android
  • 配置了網路適配和資料轉換的工廠
  • Executor執行非同步回撥,這裡只是預設值的初始化,還沒有真正部署到Retrofit的成員變數中

總結

這部分主要介紹了Retrofit的builder構建者模式以及builder內部類的成員變數的作用,接下來會繼續學習分析Retrofit的原始碼

未完待續