看過很多篇 Retrofit 的源碼分析文章岗憋,但是別人一問起來總是講不清楚到底 Retrofit 是怎么個流程逸邦,所以還是得自己親自去看看源碼,一步一步的分析。果然只有親自動手實踐捐腿,才有自己的收獲。
告誡自己柿顶,慢慢來茄袖,會很快。
- 文章來源:itsCoder 的 WeeklyBolg 項目
- itsCoder主頁:http://itscoder.com/
- 作者:謝三弟
- 審閱者:Joe
目錄
Retrofit 簡介
Retrofit 源碼開頭的解釋
* Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to
* define how requests are made. Create instances using {@linkplain Builder
* the builder} and pass your interface to {@link #create} to generate an implementation.
Retrofit 利用方法上的注解將接口轉(zhuǎn)化成一個 HTTP 請求嘁锯。
簡單知道是什么了之后宪祥,我們對此提出疑問:
- 如何將接口轉(zhuǎn)換為網(wǎng)絡請求?
- 誰去進行網(wǎng)絡請求家乘?
接下來我們將從 Retrofit 的使用作為入口分析蝗羊。
Retrofit 分析
具體使用
首先建立 API 接口類:
interface GankApi {
String host = "http://gank.io/api/data/";
@GET("Android/10/{page}")
Call<Android> getAndroid(@Path("page") int page);
}
// 創(chuàng)建 Retrofit 實例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(GankApi.host)
.addConverterFactory(GsonConverterFactory.create())
.build();
// 生成接口實現(xiàn)類
GankApi gankApi = retrofit.create(GankApi.class);
// 調(diào)用接口定義的請求方法,并且返回 Call 對象
Call<Android> call = gankApi.getAndroid(1);
// 調(diào)用 Call 對象的異步執(zhí)行方法
call.enqueue(Callback callback)
簡單的使用就是這樣的流程∪示猓現(xiàn)在我們開始層層剖析耀找。
工具箱:Retrofit.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;
創(chuàng)建 Retrofit 的實例,進行一些配置业崖,這里我們不用多說野芒。但是有一個參數(shù)必須得講講。
- Platform
在構建 Retrofit 的時候双炕,會對當前使用平臺進行判斷狞悲,Java8,Android雄家,iOS效诅。
我們看看 Android 平臺的代碼:
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);
}
}
}
從代碼中我們得知兩點:
- 在 Android 里我們默認使用的 CallAdapter 是
ExecutorCallAdapterFactory()
它會返回的是 Call.class胀滚。關于ExecutorCallAdapterFactory()
我們稍后再說趟济,你先知道這是 Android 默認 CallAdapter 就好。 - 默認的 Callback 是在主線程咽笼。
外殼:Create()
// 生成接口實現(xiàn)類
GankApi gankApi = retrofit.create(GankApi.class);
我在源碼里寫好了注釋:
public <T> T create(final Class<T> service) {
// 檢查傳入的類是否為接口并且無繼承
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
// 重點是這里
// 首先會返回一個利用代理實現(xiàn)的 GankApi 對象
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
// 我們調(diào)用該對象的方法都會進入到這里
@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);
}
// 解析方法 這里用到了注解(Runtime)這里我們標記下(A)稍后來看看里面具體實現(xiàn)
ServiceMethod serviceMethod = loadServiceMethod(method);
// 將剛剛解析完畢包裝后的具體方法封裝成 OkHttpCall 顷编,你可以在該實現(xiàn)類找到 okhttp 請求所需要的參數(shù)
// 所以它是用來跟 okhttp 對接的。
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 將以上我們封裝好的 call 返回給上層剑刑,這個時候我們就可以執(zhí)行 call 的同步方法或者異步進行請求媳纬。
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
切合我們實際運用來看看順序:
GankApi gankApi = retrofit.create(GankApi.class);
—->
return (T) Proxy.newProxyInstance(...){...}
—->
Call<Android> call = gankApi.getAndroid(1);
—->
public Object invoke(...){...}
調(diào)用代理類的invoke()
。
直到這里我們已經(jīng)宏觀地了解 Retrofit 是怎樣的一個流程施掏。
達成 初窺門徑 成就钮惠。
千萬別驕傲,為了以后走的更遠更穩(wěn)七芭,我們得好好筑基素挽,上面我們用到的是動態(tài)代理,強烈建議認真閱讀兩篇文章狸驳。
結構:ServiceMethod
Retrofit 有一個雙鏈表用來緩存方法
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
// 從緩存中獲取該方法
result = serviceMethodCache.get(method);
if (result == null) {
// 沒有就進行創(chuàng)建并且存入鏈表緩存
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
我們發(fā)現(xiàn)主要的方法是 new ServiceMethod.Builder(this, method).build();
预明,所以接下來我們深入看看如何 解析注解 以及 構建請求方法 缩赛。
- 初始化一些參數(shù)
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
build()
這里的源碼很長,做了很多異常處理撰糠,我截取重點來分析下酥馍。
callAdapter = createCallAdapter();
responseConverter = createResponseConverter();
一個是用來發(fā)送請求的 client ,一個是結果的轉(zhuǎn)換器(Gson阅酪,F(xiàn)astJson ...)之類旨袒,后面我們再講這個。
上層配置就是當我們調(diào)用 Retrofit 的 addConverterFactory()
和 addCallAdapterFactory()
术辐,內(nèi)部會自動使用我們定義的組件峦失。
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
在這里可以看到遍歷我們使用方法的注解,并且解析他們术吗。parseMethodAnnotation()
內(nèi)部就是解析好 HTTP 的請求方式尉辑。
為了篇幅大小,可以在 源碼 里看看具體的操作较屿。
同時也可以看看 http 包下注解用到的接口隧魄,你會發(fā)現(xiàn) @Retention(RUNTIME)
所以,從這里我們就可以明白隘蝎,Retrofit 是在在運行期通過反射訪問到這些注解的购啄。
return Call
請求方法參數(shù),請求客戶端嘱么,返回值轉(zhuǎn)換狮含,我們都定義好了之后,便完成最后一步曼振,構建好適合請求客戶端的請求方法几迄,Retrofit 默認的是 okhttpCall 。
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
最后將 call 返回給上層冰评,用戶調(diào)用方法進行請求映胁。
- 總結
/** Adapts an invocation of an interface method into an HTTP call. */
ServiceMethod 類開頭注釋已經(jīng)很清楚的說明了作用,將接口方法改變成一個 HTTP call 甲雅。它對于 Retrofit 是很重要的存在解孙,整個槍支內(nèi)部都是由它來支撐起來。
子彈:xxxFactory()
Retrofit 給我們最大的便利就是自身框架優(yōu)雅的設計抛人,只需要很小的改動弛姜,便可以優(yōu)雅的適應不同的需求。所以很需要我們再補充點額外知識妖枚,了解什么是適配器模式廷臼,然后回到這里看看 Retrofit 是如何應用的。
在構建 ServiceMethod
對象的時候,有三個方法可以單獨說說
-
build()
中createCallAdapter()
—->retrofit.callAdapter()
- 解析接口方法內(nèi)注解時
parseParameterAnnotation()
調(diào)用到的retrofit.requestBodyConverter()
-
build()
中createResponseConverter()
—->retrofit.responseBodyConverter()
callAdapter()
最終會調(diào)用到 nextCallAdapter()
該方法主要是從 callAdapterFactories 中獲取新的 CallAdapter中剩,它會跳過 skipPast忌穿,以及 skipPast 之前的 Factory,然后找到與 returnType 和 annotations 都匹配的 CallAdapterFactory 结啼。
requestBodyConverter() & responseBodyConverter()
最終會調(diào)用到 nextRequestBodyConverter()/nextResponseBodyConverter
利用 converterFactories 創(chuàng)建一個與 RequestBody/ResponseBody 對應的 Converter 對象掠剑。
所以在這里我們就可以裝填我們需要的子彈類型了。
進入實戰(zhàn)郊愧,為我們的 Retrofit 添加 RxJava 和 Gson朴译。
- Rxjava:
adapter-rxjava 我們重點看 RxJavaCallAdapterFactory 即可,它是實現(xiàn)了 CallAdapter.Factory 并在對應方法里將 Call 包裝成 Observable.class 返回属铁。
然后給 Retrofit 對象加上 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
眠寿,這樣我們才可以優(yōu)雅的使用 Retrofit + RxJava 。
- Gson:
我相信通過類名我們就可以知道每個類是用來做什么的焦蘑,我在這里太過深入到具體實現(xiàn)反而一葉障目盯拱,
如果我們需要自定義數(shù)據(jù)轉(zhuǎn)換格式,也是同樣這樣做例嘱。
繼承 Converter.Factory
類作為適配類狡逢,同時創(chuàng)建兩個實現(xiàn) Converter
的類包裝請求和響應的數(shù)據(jù)形式。
開槍打靶: Call.enqueue()
<div class="tip">
注意:我這里只列舉一個默認狀態(tài)下的情況
</div>
?還記得我工具箱里我們提到的 ExecutorCallbackCall
嗎拼卵?
這里的 Call 是對應我們選擇的 call 奢浑,而此時是默認的 ExecutorCallbackCall
。如果還要問我為什么腋腮,請去看看 工具箱:Retrofit.Builder() 里 Android 平臺的源碼雀彼。
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
// 省略
}
這里的 delegate 對應的就是 okhttp 的 call ,不禁有疑問了即寡,這里調(diào)用的是異步請求徊哑,但是我們的回調(diào)是怎么回到主線程的呢?
帶著疑問我們來看看嘿悬。
首先回調(diào)是在 callbackExecutor.execute()
我們從這里入手实柠。
我們發(fā)現(xiàn)在 Retrofit 的 build()
方法里:
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
平臺默認的回調(diào)調(diào)度器,連忙回到工具箱看看:
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);
}
}
}
我們發(fā)現(xiàn)善涨,Android 默認的調(diào)度器是主線程的 Handler ,execute()
方法也只是 mainHandler.post()
草则。
所以這下就可以解決我們的疑問了钢拧。
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
這段代碼我們就可以改寫為:
mainHandler.post(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
如果看到這,還不理解為什么那就得好好補補 handler 的知識啦炕横!
我這里推薦 melo 寫的這篇源内,風趣易懂 帶著這篇去通關所有Handler的提問 。
最后放上兩張開源社區(qū)畫的流程圖份殿,我覺得特別清晰:
以上膜钓∷越唬〃′?`)