前一章節,先系統的講解了關於Retrofit
實現當中的主要技術動態代理,本篇詳細結合動態代理在Retrofit
中的應用,擴展到結合RxJava
來使用html
要深刻研究一款開源項目最好的入口就是它所暴露出來的外部使用接口,按照這個思路,因此須要大致先了解Retrofit
的基本使用,這裏就不闡述這些基礎的知識,能夠查看之前的博客git
RxRetrofit-專欄github
想要弄清楚 Retrofit 的細節,先來看一下 Retrofit 源碼的組成:設計模式
一個 retrofit2.http 包,裏面所有是定義 HTTP 請求的註解,好比 GET、POST、PUT、DELETE、Headers、Path、Query 等等數組
餘下的 retrofit 2.0 包中十幾個類和接口就是所有 retrofit 的代碼了,代碼真的不多,很簡單,由於retrofit把網絡請求這部分功能所有交給了 okHttp 了緩存
先上一段使用Retrofit開始前的初始代碼網絡
//手動建立一個OkHttpClient並設置超時時間緩存等設置
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(basePar.getConnectionTime(), TimeUnit.SECONDS);
/*建立retrofit對象*/
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(basePar.getBaseUrl())
.build();複製代碼
這裏的入口Builder()
方法進入源碼ide
public static final class Builder {
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
xxxx複製代碼
Builder類中主要是記錄請求過程當中的一些配置信息,好比基礎url
,固然重要的是addConverterFactory
方法記錄Converter
數據轉換器;addCallAdapterFactory
方法記錄CallAdapter-HTTP
請求返回數據的類型.工具
Converter
數據轉換器Converter
數據轉換器默認存放在retrofit-converters
中
Converter
採用接口抽象的方式,靈活了轉換器的種類,經常使用的如上圖中的Gson
和String
,一樣這裏能夠能夠自由擴展,實現Converter.Factory
接口
CallAdapter
請求返回數據的類型工程位置如圖
這裏同Converter
數據轉換器思想同樣一樣是採用抽象接口的方式,繼承CallAdapter.Factory
類實現擴展,正如上圖中箭頭指示的顯示擴展的RxJava2
的擴展
在Builder
記錄完數據後經過build()
方法,將收集的信息傳遞給最後的Retrofit
對象中,而且初始了okhttp3.Call.Factory
請求處理類,從中能夠看出Retrofit2.0
底層的http
請求默認就是經過okhttp3
處理的。
/** * Create the {@link Retrofit} instance using the configured values. * <p> * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link * OkHttpClient} will be created and used. */
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}複製代碼
Retrofit
初始完成之後,須要調用create
方法傳入一個java接口抽象類對象做爲參數。其實這一步真是Retrofit
動態代理生成的地方
源碼:
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}複製代碼
使用代碼:
HttpTestService httpService = retrofit.create(HttpTestService.class);
httpService.getAllVedioBy(isAll());複製代碼
上面HttpTestService
對象實際上是一個動態代理對象,並非一個真正的 HttpTestService
接口的implements
對象,當 httpService
對象調用 getAllVedioBy
方法時,執行的是下面動態代理方法。
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);複製代碼
其中主要ServiceMethod
是主要的處理對象
ServiceMethod
信息類當調用loadServiceMethod
方法,將抽象HttpTestService中經過註解定義的信息收集起來存放於ServiceMethod
中,其中主要包含了一下數據:
OkHttpClient:發送網絡請求的工具
RequestFactory: 相似於 Volley 中的 Request,包含了HTTP請求的Url、Header信息,MediaType、Method以及RequestAction數組
CallAdapter:HTTP請求返回數據的類型
Converter:數據轉換器
最後Map<Method, ServiceMethod> serviceMethodCache
保存所有的 ServiceMethod
信息類
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}複製代碼
debug
可查看當前ServiceMethod
對象收集的信息
收集完信息之後執行了
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);複製代碼
這一步對okhttp熟悉的同窗確定知道了,就是經過okhttp請求數據,其中serviceMethod是請求的地址信息,args是當前接口須要的參數信息。
執行完http請求之後,執行了
serviceMethod.callAdapter.adapt(okHttpCall);複製代碼
這一步是將okhttp獲取到的數據傳遞給一開始Retrofit
經過builder
指定的RxJavaCallAdapterFactory
類,那它是如何一步步處理的呢?
其實在一開始的獲取serviceMethod
方法loadServiceMethod(Method method)
中,已經將Retrofit
對象傳遞給了serviceMethod
對象
核心代碼:
//這裏的this便是`Retrofit`對象
result = new ServiceMethod.Builder(this, method).build();複製代碼
經過.Builder(this, method).build()
方法將Retrofit
一開始的builder
信息所有傳遞給瞭如今的serviceMethod
對象,因此當執行
serviceMethod.callAdapter.adapt(okHttpCall);複製代碼
serviceMethod.callAdapter
便制動轉換成了RxJavaCallAdapterFactory
,調用CallAdapter
抽象接口adapt
進入到RxJavaCallAdapterFactory
類中
源碼:
@Override public <R> Observable<Response<R>> adapt(Call<R> call) {
Observable<Response<R>> observable = Observable.create(new CallOnSubscribe<>(call));
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
}複製代碼
最後生成RxJava
的Observable
對象,後面經過獲得的Observable
對象就是對數據的處理了。
到此基於Retrofit
結合RxJava
源碼的解讀就完成了,回頭看整個過程其實仍是很簡單,做者條理清晰理解起來也很簡單,一口氣終於把Retrofit
大致擼了一遍。
Retrofit
很是巧妙的用註解來描述一個 HTTP
請求,將一個 HTTP
請求抽象成一個 Java
接口,而後用了 Java
動態代理的方式,動態的將這個接口的註解「翻譯」成一個 HTTP
請求,最後再執行這個 HTTP
請求
Retrofit
的功能很是多的依賴 Java
反射,代碼中其實還有不少細節,好比異常的捕獲、拋出和處理,大量的 Factory
設計模式。
Retrofit
中接口設計的恰到好處,在你建立 Retrofit
對象時,讓你有更多更靈活的方式去處理你的需求,好比使用不一樣的 Converter
、使用不一樣的 CallAdapter
,這也就提供了你使用 RxJava
來調用 Retrofit
的可能。