手撕Retrofit原始碼設計(二)
技術標籤:androidjavaretrofitokhttp
上一篇中大致對比了okhttp和retrofit傳送請求的大致流程,瞭解okhttp的工作流程對掌握retrofit是非常重要的。本篇繼續講解retrofit的內部構成。retrofit使用Builder模式完成構建,通過Builder模式開發者可以配置常用的GsonConvertFactory完成json資料例項化,也可以新增RxJava2CallAdapterFactory進行自定義請求,最終這些額外的配置都被儲存在Retrofit的例項當中。下面先來看Retrofit的屬性都有哪些:
public final class 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; ··· }
serviceMethodCache
serviceMethodCache是一個儲存ServiceMethod的map。ServiceMethod是一個非常重要的類,我們在介面中定義的每一個請求方法最終都會在執行時被解析,方法註解中的所有資訊都會被儲存在一個ServiceMethod物件中。當方法被呼叫時,retrofit通過動態代理拿到執行時Method物件,根據Method物件構建一個ServiceMethod物件,並呼叫ServiceMethod的invoke方法完成最終的請求。
callFactory
callFactory是Okhttp中定義的介面,並不是retrofit定義的。他的作用就是建立網路請求的真正的Call物件。通過引用介面,開發者就可以注入自己的預設實現,達到多型的效果。他有一個預設的實現類大家都不會陌生:OkHttpClient。上一篇中我們說過retrofit是通過okhttp完成的網路請求,實際的體現就是這裡。
package okhttp3;
public interface Call extends Cloneable {
···
interface Factory {
Call newCall(Request request);
}
}
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
···
}
baseUrl
這個類比較簡單,就是用來儲存baseUrl,不再多說。
converterFactories
Converter.Factory是retrofit中定義的類。我們知道在okhttp的回撥方法中,最終的返回值是一個固定的型別Response。通過response.body()方法可以獲取到ResponseBody物件進而通過responseBody.string()方法獲取body的實際內容,這些型別都是固定的需要我們自己對返回結果進行手動解析。
但是在retrofit中,在資料請求成功回撥後,retrofit會在converterFactories列表中根據介面中方法的返回值Call<T>的泛型T,選擇一個合適的轉化器工廠,自動進行型別轉化.
package retrofit2;
public interface Converter<F, T> {
@Nullable
T convert(F value) throws IOException;
abstract class Factory {
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
···
}
}
Converter.Factory有一個預設的實現類BuiltInConverters,在建立retrofit的時候會永遠把BuiltInConverters放在converterFactories列表的第一個。BuiltInConverters是 retrofit 提供的預設資料轉化器工廠,他的轉化只是將ResponseBody直接快取返回,並沒有其他額外的工作。所以如果在介面中定義的方法的返回值是Call<ResponseBody>的時候,這時候retrofit就會使用BuiltInConverters進行資料轉化。
如果我們又向retrofit中添加了GsonConvertFactory,此時介面中方法的返回值就可以寫成這樣Call<User>,這時泛型不再是ResponseBody而是User,retrofit就會選擇使用GsonConvertFactory進行資料轉化。然後在回撥中我們就可以直接獲取到User物件了。
callAdapterFactories
這裡retrofit使用介面卡模式對最原始的okhttp中的Call物件進行一層層的裝飾,每一層的包裝都可以完成一些自定義的對Okhttp的Call的操作,比例:執行緒切換。在構建ServiceMethod的時候,retrofit會根據介面中定義方法的返回值型別去callAdapterFactories中查詢符合要求的adapter工廠。
CallAdapter.Factory也是retrofit提供的一個抽象的工廠類。
package retrofit2;
public interface CallAdapter<R, T> {
···
abstract class Factory {
···
}
}
DefaultCallAdapterFactory是該類的預設實現,在構建retrofit時會自動新增到callAdapterFactories列表中。DefaultCallAdapterFactory只會處理介面中方法返回值為Call<T>的型別。所以在預設情況下我們必須將介面中方法的返回值定義為Call<T>型別,否則會丟擲異常。
如果我們又為retrofit添加了RxJava2CallAdapterFactory,那麼此時介面中定義的方法就可以返回Observable<T>了,然後我們就可以使用RXJava的方式進行請求。但是此時callAdapterFactories列表中只有DefaultCallAdapterFactory和RxJava2CallAdapterFactory兩個工廠,也就是說現在介面中方法可以接受的返回值有Call<T>和Observable<T>兩種型別。如果你寫一個String型別,那麼同樣會丟擲異常。
callbackExecutor
就是有個普通的執行緒池,他的預設實現是一個通過Handler在主執行緒執行的類,retrofit預設的執行緒排程就是通過這個執行緒池。
package retrofit2;
class Platform {
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
總結
可以看到retrofit的設計處處都透露著設計模式和程式碼的基本原則。在retrofit中引用了三種抽象的工廠,開發人員可以注入自己的工廠實現。用裝飾器模式對okhttp的Call進行自定義的處理達到執行緒切換的效果、通過動態代理執行網路請求等等。本篇從整體介紹了retrofit內部成員的職責,下一篇中將開始系統的講解retrofit是如何傳送網路請求到資料解析的整個流程。