該篇直接介紹Retrofit的原理,如果你還不是很熟悉retrofit的使用,可以看筆者對retrofit之前寫過的詳細介紹查看傳送門
1.Retrofit中的create()方法分析
通過Reftrofit.create(Class)方法,創建出Service inteface的實例,從而使得Service中配置的方法變的可用,即這是Retrofit的代碼結構的核心
public <T> T create(final Class<T> 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, @Nullable Object[] args)
throws Throwable {
//....
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
通過以上代碼核心方法,可以看到實例是通過Proxy.newProxyInstance()創建的,這個方法會爲參數中的多個interface創建一個對象,這個對象實現了interface中定義的所有方法,並且每個方法的實現雷同,調用對象實例內部的一個InvocationHandler成員變量的invoke()方法,並把自己的方法信息傳遞進去,這樣就在實質上實現了代理邏輯。並且這些方法的具體實現是在運行時生產interface實例時才確定。
- loadServiceMethod()該方法負責讀取interface中原方法的信息,(包括返回值類型,方法註解,參數類型,參數註解),並將這些信息初步分析及校驗
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
- 那麼可以分析loadServiceMethod(method)做了什麼事?根據method參數,構造一個ServiceMethod對象,那麼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;
}
2. 接下來再看看ServiceMethod中是什麼東西?爲什麼將處理的方法都封裝爲ServiceMethod
- 以下是源碼:
final class ServiceMethod<R, T> {
final okhttp3.Call.Factory callFactory;
final CallAdapter<R, T> callAdapter;
private final HttpUrl baseUrl;
private final Converter<ResponseBody, R> responseConverter;
...
ServiceMethod(Builder<R, T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
//...
}
-
ServiceMethod中大致有以下成員變量及說明:
-
CallAdapter //這裏會根據平臺信息,返回Default或者說自定義的,比如RxJava2CallAdapter,默認實現的一個CallAdapter則實現了android線程的切換,通過Handler將線程切回到主線程。即Android
-
Converter //如GsonConvertAdapter,將okhttp的response轉爲json的處理adapter
-
Okhhtp3.Call.Factory 即配置的OkhttpClient
-
method //方法名
-
Annotation[] methodAnnotations //方法註解
-
Annotation[][] parameterAnnotationsArray //方法參數
-
ServiceMethod中保存了Http請求的所有的參數和當前方法需要調度的Call和Convert
方法 -
使用Map將method於ServiceMethod用於緩存,提高全局訪問的性能
3.開始創建OKHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
當封裝完method轉化爲ServiceMethod後,執行上面這句,則創建出OkhttpCall對象,即將ServiceMehod中封裝的信息和參數,準備好這些資源以後,則全部交個OkhttpCall,從 OkHttpCall 這個名字來看就能猜到,它是對 OkHttp3.Call 的組合包裝,事實上,它也確實是。(OkHttpCall中有一個成員okhttp3.Call rawCall)。當然跟進去發現瞭如下代碼,是不是很熟悉?,顯然這是okhttp請求網絡的流程的真正開始的地方。可以看筆者之前對okhttp源碼分析的一系列文章傳送門
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
封裝爲Okhttp所需要的request對象,然後newCall創建一個
RealCall.newRealCall(this, request, false /* for web socket */);
則開始執行一個okhttp請求方法,至於okhttp如何網絡請求,這裏請參看筆者之前寫的okhttp的源碼的分析,這裏不做過多的研究,
4.執行CallAdapter
當執行Call.enqueue()方法後,或者說如果結合Rxjava進行訂閱了以後,則調用Okhttp的enqueue()方法,通過createCall()方法,得到OkhttpClient中返回的Response,然後根據之前在ServiceMethod中封裝的ConverAdapter方法,將Response進行
response = parseResponse(rawResponse);
parseResponse核心方法
T body = serviceMethod.toResponse(catchingBody);
5. 執行convertAdapter
responseConverter.convert(body)
因爲在初始化Retrofit的時候設置了ConverterFactory爲
Retrofit.create(ApiService.class)
...
.addConverterFactory(GsonConverterFactory.create())
...
則使用GsonConverterFactory處理catchingBody,這裏在看看GsonConverterFactory的方法
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
到這裏,retrofit的請求網絡的大體流程則完成。
總結
Retrofit 使用了動態代理給將我們定義的接口設置了代理,當調用接口的方法時,Retrofit 會攔截下來,然後經過一系列處理,其實可以參考如下代碼,動態代理做的事情如下:
public interface Github{
@GET("user/get")
Call<List<User>> getUser();
@GET("user/getUserInfo")
Call<User> getUserInfo();
}
public class RealService implements Github{
InvocationHandler invocationHandler = new InvocationHandler(){
@Override
public Object invock(Object proxy ,Method method,@Nullable Object[] args){
//扮演代理身份,對不同的方法不同的處理
}
}
@Override
public Call<List<User>> getUser(){
try{
Method method = Github.class.getMethod("getUser");
return invocationHandler.invock(this,method,null);
}catch(Exception e){
e.printStackTrace();
}
}
}
比如解析方法的註解和參數,生成了 Call 、Request 、等OKHttp所需的資源,最後交給 OkHttp 去發送請求, 此間經過 callAdapter,convertr 的處理。
在callAdapter處理的過程中,會將okhttp中的call,轉化爲Observable(自定義設定的,即使沒有,也會根據平臺創建一個默認的),最終執行call.execute(),開始真正的請求
將請求得到的結果通過convertAdapter處理後,轉化爲定義的返回類型,然後根據處理結果進行回調
即:Retrofit 中的數據其實是交給了 callAdapter 以及 converter 去處理,callAdapter 負責把 okHttpCall 轉成我們所需的 Observable類型,converter負責把服務器返回的數據轉成具體的實體類。