前言
在上一周學習了一下 Retrofit 的執(zhí)行流程。接下來的文章要更為深入地學習 Retrofit 的各個類荸百,這次我們先學習一下 Retrofit 框架里的 Retrofit 對象囚似,有沒有十分的拗口剩拢。。
本文主要講 Retrofit 對象的創(chuàng)建及其 .create 方法饶唤⌒旆ィ基本包括了這個類的全部內(nèi)容。
Retrofit 對象
簡介
Retrofit 通過使用方法上的『注解』來定義請求的構(gòu)成募狂,將我們聲明的 Http 接口轉(zhuǎn)化成一個 Call 對象呵晨。
這個 Call 對象呢,我們上周提到過熬尺,可以調(diào)用同步或非同步方法來發(fā)送請求摸屠,之后就交給 OkHttp 去執(zhí)行啦。
使用
Retrofit 類用到了創(chuàng)建者模式粱哼,我們需要使用 Retrofit.Builder 來創(chuàng)建它的實例季二,接著調(diào)用 Retrofit.create(Class<T>) 方法就能夠生成我們的接口實現(xiàn)類了。
這里回顧一下 Retrofit 相關(guān)的使用:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
MyApi api = retrofit.create(MyApi.class);
Retrofit.Builder
Retrofit.Builder 是 Retrofit 對象的一個嵌套類,負責用來創(chuàng)建 Retrofit 實例對象胯舷,使用『建造者模式』的好處是清晰明了可定制化刻蚯。
在執(zhí)行 .build() 方法前,只有 .baseUrl() 是必須調(diào)用來設置訪問地址的桑嘶,其余方法則是可選的炊汹。
首先看一下 Builder.build() 最后的返回語句:
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
這里的參數(shù)包括了 Call 工廠,地址逃顶,轉(zhuǎn)換器讨便,CallAdapter 工廠, 執(zhí)行 Callback 的線程池以及 validateEagerly 標識以政。
下面我們挑選其中幾個參數(shù)來進行分析:
baseUrl
baseUrl 其實是 okHttp3 的 HttpUrl 類實例霸褒,一個 http 或者 https 協(xié)議的 URL。
為 Retrofit.Builder 添加 baseUrl盈蛮,有兩個重載的方法 baseUrl(String baseUrl) 和 baseUrl(HttpUrl baseUrl)废菱,但實際最后調(diào)用的都是后者。
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
可以看到抖誉,檢查驗證后就設置了 Retrofit 對象的 URL殊轴。
callbackExecutor
callbackExecutor 是 Callback 調(diào)用中用于執(zhí)行 Callback 的 線程池。
如果不自行設置的話袒炉,會根據(jù)平臺設置一個默認的 Executor梳凛。
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
這里的 .defaultCallbackExecutor() 是 Platform 抽象類的一個方法。包含了 Converter梳杏,Client 等屬性。他有三個實現(xiàn)類:Android淹接,Java8十性,IOS。分別設置了各個平臺下的一些默認參數(shù)塑悼。
在創(chuàng)建 Retrofit.Buidler 時會獲取并設置當前環(huán)境的 Platform:
public Builder() {
this(Platform.get());
}
最后我們找到 Platform 的安卓實現(xiàn)類看一下:
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
了解過 Handler 機制的同學肯定十分眼熟劲适,這里獲取了主線程的 Looper 并構(gòu)造了一個 主線程的 Handler,于是在 Android 平臺厢蒜,調(diào)用 Callback 時會將該請求 post 到主線程上去執(zhí)行霞势。
validateEagerly 標識
validateEagerly 是一個布爾類型的參數(shù)
我們知道當我們調(diào)用接口方法時,代理類會為方法創(chuàng)建一個 ServiceMethod斑鸦。
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
...
}
如果將 validateEagerly 標識設置為 True愕贡,那么在我們調(diào)用 .eagerlyValidateMethods(service) 方法之前就提前驗證并創(chuàng)建好啦。
以上便是 Retrofit.Builder 的一些參數(shù)和方法巷屿,更具體的大家可以參照官方文檔來學習固以。
.create 方法
現(xiàn)在我們通過嵌套類 build 了一個 Retrofit 對象,就可以開始執(zhí)行下一步了。
// 將 Http 接口 轉(zhuǎn)化為 Call 對象
MyApi api = retrofit.create(MyApi.class);
我們先直接把 create 方法的代碼丟上來憨琳,代碼并不是很多:
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);
}
});
}
下面一步步進行分析:
Utils.validateServiceInterface(service);
validateServiceInterface(service) 會驗證我們的 Http 接口是否是 Interface诫钓,是否未包含了其他的接口。若為否則會拋出錯誤篙螟。
if (validateEagerly) {
eagerlyValidateMethods(service);
}
validateEagerly 的標簽的作用則在之前已經(jīng)說過了菌湃,算是一個提前驗證標識。
接下來便返回了一個動態(tài)代理遍略,其實仔細看會發(fā)現(xiàn)這里只是返回了動態(tài)代理的實例方法而已:
return (T) Proxy.newProxyInstance(...);
代理類首先獲取了當前的平臺 Platform惧所,然后當你調(diào)用接口方法時,會調(diào)用到代理類的 invoke 方法墅冷。
我們看看 invoke 方法里到底做了什么:
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
如果我們調(diào)用的是來自 Object 類或者平臺默認的方法纯路,則會交給方法執(zhí)行或者平臺執(zhí)行,但從代碼上看 isDefaultMethod(method) 直接返回的是 false寞忿,可能是為了方便開發(fā)者擴展設置各個平臺的不同方法調(diào)用驰唬。
ServiceMethod serviceMethod = loadServiceMethod(method);
經(jīng)過兩個判斷后,會將我們的方法轉(zhuǎn)換成一個 ServiceMethod 對象腔彰,我們可以來看看 loadServiceMethod 方法內(nèi)發(fā)生了什么:
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
代碼很簡單叫编,每個 Method 對應一個 ServiceMethod,如果緩存里沒有霹抛,則新建一個搓逾。至于這個 ServiceMethod 是什么呢?我們具體可能要以后再詳細分析杯拐。
這里簡單的了解一下:之前我們說 Retrofit 對象的作用是將我們聲明的 Http 接口轉(zhuǎn)化成一個 Call 對象霞篡。實際上真正的工作是由 ServiceMethod 的來完成的,在其內(nèi)部分析并轉(zhuǎn)換了我們自定義的注解端逼,并生成了一個 Call 對象朗兵。
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
接下來創(chuàng)建了一個 OkHttpCall。并使用 serviceMethod.CallAdapter 對 OkHttpCall 進行了轉(zhuǎn)化顶滩。
我們在創(chuàng)建 serviceMethod 時余掖,傳入了 Retrofit 對象作為參數(shù),這個 CallAdapter 就是從我們最開始構(gòu)建 Retrofit 時所添加的 CallAdapterFatory所生成的礁鲁。如果你沒有設置的話盐欺,在 Android 平臺,系統(tǒng)會為你設置一個 ExecutorCallAdapterFactory仅醇。
ExecutorCallAdapter會先返回一個 CallAdapter 實現(xiàn)類冗美,.adapt(okHttpCall) 就是這個類的方法。
終于析二,callAdapter.adapt 把 okHttpCall 轉(zhuǎn)化成了 ExecutorCallbackCall:
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
于是我們就完成了 .create() 方法的調(diào)用墩衙,實際上 Retrofit 的使用我們也幾乎掌握了,因為之后的事情是交給 okHttp 去做的。
我們可以看看這個 ExecutorCallbackCall<>(callbackExecutor, call)漆改,參數(shù)里的 callbackExecutor心铃,有沒有很眼熟,之前 Retrofit.Builder 我們提到的默認添加的 Executor挫剑,這里其實就是我們 APP 應用的主線程去扣。
也就是我們的網(wǎng)絡請求完成后 Callback 回調(diào)的 onResponse 和 onFailure 方法,都會 post 到主線程上的 Handler 來執(zhí)行樊破。
總結(jié)
似乎這次文章的內(nèi)容有點長愉棱?總結(jié)一句話就是:Retrofit 如何將 Http 接口方法調(diào)用轉(zhuǎn)換成一個 Call 請求類。
這次我在學習代碼和寫文章到最后時哲戚,確實發(fā)現(xiàn)了之前的許多錯誤奔滑。目前難免會有許多理解不到位的地方,文章也寫的比較散亂顺少,希望各位能多多提出意見。