【一起學習Android開源框架】Retrofit原始碼解析-1(第四部分)
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內部類
- 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的原始碼
未完待續
- 請收下這些Kotlin開發必知必會的編碼實踐方式
- 日常思考,目前Kotlin協程能完全取代Rxjava嗎
- 誇誇其談,簡單說說HTTP的優化歷程
- 【一起學習開源框架】Retrofit相對於OKHttp,解決了什麼問題
- Kotlin Sequences Api:入門
- 【日常小問題】談談Rxjava中的操作符以及幾種常見的Subject,應用到實際場景中
- 【一起學習Android開源框架】Retrofit原始碼解析-1(第四部分)
- 【日常小問題】解決BottomSheetDialogFragment中多個fragment滑動衝突
- 【一起學習Android開源框架】Retrofit註解解析(第三部分)
- 【一起學習Android開源框架】Retrofit使用的代理模式解析(第二部分)
- 【一起學習Android開源框架】Retrofit的簡單使用(第一部分)