Android Retrofit原始碼解析:都能看懂的Retrofit使用詳解
你在使用 Retrofit 的時候,是否會有如下幾點疑惑?
-
什麼是動態代理?
-
整個請求的流程是怎樣的?
-
底層是如何用 OkHttp 請求的?
-
方法上的註解是什麼時候解析的,怎麼解析的?
-
Converter 的轉換過程,怎麼透過 Gson 轉成對應的資料模型的?
-
CallAdapter 的替換過程,怎麼轉成 RxJava 進行操作的?
-
如何支援 Kotlin 協程的 suspend 掛起函式的?
關於 Kotlin 協程請求網路,首先寫一個 Demo 來看一下用協程是怎麼進行網路請求的,然後會再具體分析怎麼轉換成 Kotlin 的協程的請求
我會在文章中,透過原始碼,逐步解開疑惑,並且在最後文章結尾會再次總結,回答上面的幾個問題。
友情提示,本文略長但是沒有廢話,實打實的乾貨,學習需要耐心
Retrofit和 OkHttp是目前最廣泛使用的網路請求庫了,所以有必要了解它的原始碼,學習它的優秀的程式碼與設計,來提升自己。
本文的整體思路
首先先看一下 Retrofit 的基本用法,根據示例程式碼,作為分析原始碼的依據,以及分析原始碼的入口,來一步一步看一下 Retrofit 的工作機制。
本文的依賴
implementation 'com.squareup.okhttp3:okhttp:4.8.1'implementation 'com.squareup.retrofit2:retrofit:2.9.0'implementation 'com.squareup.retrofit2:converter-gson:2.5.0'implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.2'implementation 'com.google.code.gson:gson:2.8.6'implementation 'io.reactivex.rxjava3:rxjava:3.0.0'implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'複製程式碼
1.什麼是Retrofit
Retrofit:A type-safe HTTP client for Android and Java。一個型別安全的 Http 請求的客戶端。
底層的網路請求是基於 OkHttp 的,Retrofit 對其做了封裝,提供了即方便又高效的網路訪問框架。
2.Retrofit的基本用法
class RetrofitActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //初始化一個Retrofit物件 val retrofit = Retrofit.Builder() .baseUrl(") .addConverterFactory(GsonConverterFactory.create()) .build() //建立出GitHubApiService物件 val service = retrofit.create(GitHubApiService::class.java) //返回一個 Call 物件 val repos = service.listRepos("octocat") //呼叫 enqueue 方法在回撥方法裡處理結果 repos.enqueue(object : Callback<List<Repo>?> { override fun onFailure(call: Call<List<Repo>?>, t: Throwable) { t.printStackTrace() } override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) { "response.code() = ${response.code()}".logE() } }) } } 複製程式碼
//自己定義的 API 請求介面interface GitHubApiService { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String?): Call<List<Repo>> } 複製程式碼
以上就是 Retrofit 的基本用法。
沒什麼好講的,寫這個例子就是為了分析原始碼做準備,有一個原始碼分析的入口。
3.原始碼分析的準備工作
先看幾個表面上的類
- Retrofit:總攬全域性一個類,一些配置,需要透過其內部 Builder 類構建,比如 CallAdapter、Converter 等
- GitHubApiService:自己寫的 API 介面,透過 Retrofit 的
create
方法進行例項化 - Call:Retrofit 的 Call,是執行網路請求的是一個頂層介面,需要看原始碼,具體實現類實際是一個 OkHttpCall,下面會具體說
- Callback:請求結果回撥
接下來重點來了,進行原始碼分析。
4.原始碼分析
分析的入口是我們程式碼例子中的
repos.enqueue(object : Callback<List<Repo>?> {…})
方法
點進去,看到是 Call 的
enqueue
方法
public interface Call<T> extends Cloneable { void enqueue(Callback<T> callback); } 複製程式碼
這是一個介面,是我們 GitHubApiService 介面中定義的
listRepos
方法中返回的 Call 物件,現在就要看GitHubApiService 的初始化,以及具體返回的是
Call 物件是誰。
然後重點就要看
retrofit.create(GitHubApiService::class.java)
方法,來看下 GitHubApiService 具體是怎麼建立的,以及 Call 物件的實現類
5.Retrofit 的 create 方法
//Retrofit.javapublic <T> T create(final Class<T> service) { //1 validateServiceInterface(service); //2 return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] {service}, new InvocationHandler() { private final Platform platform = Platform.get(); private final Object[] emptyArgs = new Object[0]; @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable 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); } args = args != null ? args : emptyArgs; return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); } }); } 複製程式碼
註釋 1:這個方法,就是驗證我們定義的 GitHubApiService 是一個介面,且不是泛型介面,並且會判斷是否進行方法的 提前驗證,為了更好的把錯誤暴露的編譯期,這個不是我們的重點內容,具體程式碼就不看了。
註釋 2 :是一個動態代理的方法,來返回 GitHubApiService 的例項
動態代理?嗯?什麼是動態代理,接下來,我就寫一個具體的例子來展示一個動態代理的具體用法,以及什麼是動態代理?
先插播一段動態代理程式碼,這個是理解 Retrofit 的工作機制所必須的。
6.動態代理的示例
6.1.寫一個動態代理的 Demo
下面是一個 Java 專案,模擬一個 Retrofit 的請求過程
//模擬 Retrofit,定義 API 請求介面public interface GitHubApiService { void listRepos(String user); } 複製程式碼
public class ProxyDemo { //程式的入口方法 public static void main(String[] args) { //透過動態代理獲取 ApiService 的物件 GitHubApiService apiService = (GitHubApiService) Proxy.newProxyInstance( GitHubApiService.class.getClassLoader(), new Class[]{GitHubApiService.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("method = " + method.getName() + " args = " + Arrays.toString(args)); return null; } }); System.out.println(apiService.getClass()); //呼叫 listRepos 方法 apiService.listRepos("octcat"); } } 複製程式碼
執行
main
方法
當我們呼叫
apiService.listRepos("octcat");
方法時,列印出來如下結果
class com.sun.proxy.$Proxy0method = listRepos args = [octcat] 複製程式碼
可以看到當我們呼叫
listRepos
方法的時候,InvocationHandler 的
invoke
方法中攔截到了我們的方法,引數等資訊。
Retrofit 的原理其實就是這樣,攔截到方法、引數,再根據我們在方法上的註解,去拼接為一個正常的OkHttp 請求,然後執行。
日誌的第一行,在執行時這個類一個
$Proxy0
的類。實際上,在執行期 GitHubApiService 的介面會動態的建立出
實現類也就是這個
$Proxy0
類,它大概長下面這個樣子。
我做了一個點改動,方便檢視,本質上都是一樣的
class $Proxy0 extends Proxy implements GitHubApiService { protected $Proxy0(InvocationHandler h) { super(h); } @Override public void listRepos(String user) { Method method = Class.forName("GitHubApiService").getMethod("listRepos", String.class); super.h.invoke(this, method, new Object[]{user}); } } 複製程式碼
我們在呼叫
listRepos
方法的時候,實際上呼叫的是 InvocationHandler 的
invoke
方法。
6.2總結
- 在 ProxyDemo 程式碼執行中,會動態建立 GitHubApiService 介面的實現類,作為代理物件,執行InvocationHandler 的
invoke
方法。 - 動態指的是在執行期,而代理指的是實現了GitHubApiService 介面的具體類,實現了介面的方法,稱之為代理
- 本質上是在執行期,生成了 GitHubApiService 介面的實現類,呼叫了 InvocationHandler 的
invoke
方法。
現在解決了第一個疑問: 什麼是動態代理
好的,動態代理已經知道是啥了,回到我們
retrofit.create(GitHubApiService::class.java)
方法
7.再看 Retrofit 的 create 方法
//Retrofit.javapublic <T> T create(final Class<T> service) { validateServiceInterface(service); return (T) Proxy.newProxyInstance( service.getClassLoader(),//1 new Class<?>[] {service},//2 new InvocationHandler() {//3 private final Platform platform = Platform.get(); private final Object[] emptyArgs = new Object[0]; @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is a method from Object then defer to normal invocation. //4 if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } args = args != null ? args : emptyArgs; //5 return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); } }); } 複製程式碼
註釋 1:獲取一個 ClassLoader 物件
註釋 2:GitHubApiService 的位元組碼物件傳到陣列中去,也即是我們要代理的具體介面。
註釋 3:InvocationHandler 的
invoke
是關鍵,從上面動態代理的 Demo 中,我們知道,在GitHubApiService宣告的
listRepos
方法在呼叫時,會執行 InvocationHandler 的
invoke
的方法體。
註釋 4:因為有代理類的生成,預設繼承 Object 類,所以如果是 Object.class 走,預設呼叫它的方法
註釋 5:如果是預設方法(比如 Java8 ),就執行 platform 的預設方法。
否則執行
loadServiceMethod
方法的
invoke
方法
loadServiceMethod(method).invoke(args);
這個方法是我們這個 Retrofit
最關鍵的程式碼,也是分析的重點入口
7.1.先看loadServiceMethod方法
我們先看
loadServiceMethod
方法返回的是什麼物件,然後再看這個物件的
invoke
方法
//Retrofit.javaprivate final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>(); ServiceMethod<?> loadServiceMethod(Method method) { //1 ServiceMethod<?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { //2 result = ServiceMethod.parseAnnotations(this, method); //3 serviceMethodCache.put(method, result); } } return result; } 複製程式碼
註釋 1:從 ConcurrentHashMap 中取一個 ServiceMethod 如果存在直接返回
註釋 2:透過
ServiceMethod.parseAnnotations(this, method);
方法建立一個 ServiceMethod 物件
註釋 3:用 Map 把建立的 ServiceMethod 物件快取起來,因為我們的請求方法可能會呼叫多次,快取提升效能。
看一下
ServiceMethod.parseAnnotations(this, method);
方法具體返回的物件是什麼,然後再看它的
invoke
方法
7.2.ServiceMethod的parseAnnotations方法
這個方法接下來還會看,這裡我們只看現在需要的部分。
//ServiceMethod.javastatic <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) { ... //1 return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); } 複製程式碼
返回的是一個 HttpServiceMethod物件,那麼接下來看下它的 invoke 方法
7.3.HttpServiceMethod 的 invoke 方法
//HttpServiceMethod.java@Overridefinal @Nullable ReturnT invoke(Object[] args) { //1 Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); //2 return adapt(call, args); } 複製程式碼
註釋 1:建立了一個Call物件,是 OkHttpCall,這個不就是在 GitHubApiService 這個介面宣告的 Call 物件嗎?
然後再看 OkHttpCall 的
enqueue
方法,不就知道是怎麼進行請求,怎麼回撥的了嗎?
註釋 2:是一個 adapt 方法,在不使用 Kotlin 協程的情況下,其實呼叫的是子類 CallAdapted 的
adapt
,這個會在下面具體分析,包括 Kotlin 協程的 suspend 函式
現在我們已經知道了 GitHubApiService 介面中定義的
listRepos
中的 Call 物件,是 OkHttpCall,接下里看OkHttpCall 的
enqueue
方法
8.OkHttpCall的enqueue方法
這段程式碼比較長,但這個就是這個請求的關鍵,以及怎麼使用 OkHttp 進行請求的,如果解析 Response 的,如何回撥的。
//OkHttpCall.java@Overridepublic void enqueue(final Callback<T> callback) { Objects.requireNonNull(callback, "callback == null"); //1 okhttp3.Call call; Throwable failure; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; call = rawCall; failure = creationFailure; if (call == null && failure == null) { try { //2 call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } //3 call.enqueue( new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { //4 response = parseResponse(rawResponse); } catch (Throwable e) { throwIfFatal(e); callFailure(e); return; } try { //5 callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); // TODO this is not great } } @Override public void onFailure(okhttp3.Call call, IOException e) { callFailure(e); } private void callFailure(Throwable e) { try { //6 callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); // TODO this is not great } } }); } 複製程式碼
註釋 1:宣告一個 okhttp3.Call 物件,用來進行網路請求
註釋 2:給 okhttp3.Call 物件進行賦值,下面會具體看程式碼,如何建立了一個 okhttp3.Call 物件
註釋 3:呼叫 okhttp3.Call 的
enqueue
方法,進行真正的網路請求
註釋 4:解析響應,下面會具體看程式碼
註釋 5:成功的回撥
註釋 6:失敗的回撥
到現在,我們文章開頭兩個疑問得到解釋了
整個請求的流程是怎樣的?
底層是如何用 OkHttp 請求的?
我們還要看下一個 okhttp3.Call 物件是怎麼建立的,我們寫的註解引數是怎麼解析的,響應結果是如何解析的,也就是我們在 Retrofit 中配置
addConverterFactory(GsonConverterFactory.create())
是如何直接拿到資料模型的。
8.1.okhttp3.Call 物件是怎麼建立的
看下
call = rawCall = createRawCall();
方法
//OkHttpCall.javaprivate final okhttp3.Call.Factory callFactory;private okhttp3.Call createRawCall() throws IOException { //1 callFactory是什麼 okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; } 複製程式碼
透過 callFactory 建立的(callFactory應該是 OkHttpClient),看一下 callFactory 的賦值過程
//OkHttpCall.javaOkHttpCall( RequestFactory requestFactory, Object[] args, okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) { this.requestFactory = requestFactory; this.args = args; //透過 OkHttpCall 構造直接賦值 this.callFactory = callFactory; this.responseConverter = responseConverter; } 複製程式碼
在 OkHttpCall 構造中直接賦值,那接下來就繼續看 OkHttpCall 的初始化過程
//HttpServiceMethod.javaprivate final okhttp3.Call.Factory callFactory;@Overridefinal @Nullable ReturnT invoke(Object[] args) { //在 OkHttpCall 例項化時賦值, callFactory 是 HttpServiceMethod 的成員變數 Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); }//callFactory 是在 HttpServiceMethod 的構造中賦值的HttpServiceMethod( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter) { this.requestFactory = requestFactory; //透過 HttpServiceMethod 構造直接賦值 this.callFactory = callFactory; this.responseConverter = responseConverter; } 複製程式碼
發現 callFactory 的值是在建立 HttpServiceMethod 時賦值的,繼續跟!
在 7.2 小節,有一行程式碼
HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
我們沒有跟進去,現在看一下
HttpServiceMethod 是怎麼建立的
//HttpServiceMethod.javastatic <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; boolean continuationWantsResponse = false; boolean continuationBodyNullable = false; //1 okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { //2 return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } else if (continuationWantsResponse) { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter); } else { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter, continuationBodyNullable); } } 複製程式碼
註釋 1:callFactory 的值是從 Retrofit 這個物件拿到的
註釋 2:如果不是 Kotlin 的掛起函式,返回是的 CallAdapted 物件
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {} 複製程式碼
CallAdapted 是 HttpServiceMethod 的子類,會呼叫
adapt
方法進行 CallAdapter 的轉換,我們後面會詳細看。
繼續看 Retrofit 的 callFactory 的值Retrofit是透過Builder構建的,看下Builder類
//Retrofit.javapublic static final class Builder { public Retrofit build() { okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { //1 callFactory = new OkHttpClient(); } return new Retrofit( callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); } } 複製程式碼
原來 callFactory 實際是一個 OkHttpClient 物件,也就是 OkHttpClient 建立了一個 Call 物件,嗯就是 OKHttp 網路請求的那一套。
在建立okhttp3.Call 物件的
callFactory.newCall(requestFactory.create(args));
方法中的
requestFactory.create(args)
方法會返回一個 Request 的物件,這個我們也會在下面看是如何構造一個 OkHttp 的 Request 請求物件的。
8.2.請求註解引數是怎麼解析的
看
ServiceMethod.parseAnnotations(this, method);
方法
//ServiceMethod.javastatic <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) { //1 RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); ... //2 return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); } 複製程式碼
註釋 1:透過 RequestFactory 解析註解,然後返回 RequestFactory 物件
註釋 2:把 RequestFactory 物件往 HttpServiceMethod 裡面傳遞,下面會具體看 RequestFactory 物件具體幹什麼用了?
繼續跟程式碼
RequestFactory.parseAnnotations
//RequestFactory.javafinal class RequestFactory { static RequestFactory parseAnnotations(Retrofit retrofit, Method method) { //看build方法 return new Builder(retrofit, method).build(); } //build方法 RequestFactory build() { //1 for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); } .... return new RequestFactory(this); } } 複製程式碼
遍歷 GitHubApiService 這個 API 介面上定義的方法註解,然後解析註解
繼續跟程式碼
parseMethodAnnotation
//RequestFactory.javaprivate void parseMethodAnnotation(Annotation annotation) { if (annotation instanceof DELETE) { parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false); } else if (annotation instanceof GET) { parseHttpMethodAndPath("GET", ((GET) annotation).value(), false); } ... else if (annotation instanceof POST) { parseHttpMethodAndPath("POST", ((POST) annotation).value(), true); } .... else if (annotation instanceof Multipart) { if (isFormEncoded) { throw methodError(method, "Only one encoding annotation is allowed."); } isMultipart = true; } else if (annotation instanceof FormUrlEncoded) { if (isMultipart) { throw methodError(method, "Only one encoding annotation is allowed."); } isFormEncoded = true; } } 複製程式碼
就是解析方法上的註解,來存到 RequestFactory 的內部。
其實 RequestFactory 這個類還有
parseParameter
和
parseParameterAnnotation
這個就是解析方法引數宣告上的具體引數的註解,會在後面分析 Kotlin suspend 掛起函式具體講。
總之:具體程式碼就是分析方法上註解上面的值,方法引數上,這個就是細節問題了
總結就是:分析方法上的各個註解,方法引數上的註解,最後返回 RequestFactory 物件,給下面使用。
Retrofit 的大框架簡單,細節比較複雜。
RequestFactory 物件返回出去,具體幹嘛用了?大膽猜一下,解析出註解存到 RequestFactory 物件,這個物件身上可有各種請求的引數,然後肯定是類建立 OkHttp 的 Request請求物件啊,因為是用 OkHttp 請求的,它需要一個 Request 請求物件
8.3.RequestFactory 物件返回出去,具體幹嘛用了?
下面我就用一個程式碼塊貼了,看著更直接,我會具體表明屬於哪個類的
//ServiceMethod.javastatic <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) { //解析註解引數,獲取 RequestFactory 物件 RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); //把 RequestFactory 物件傳給 HttpServiceMethod return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); }//注意換類了//HttpServiceMethod.javastatic <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { ... okhttp3.Call.Factory callFactory = retrofit.callFactory; //不是 Kotlin 的掛起函式 if (!isKotlinSuspendFunction) { //把requestFactory傳給 CallAdapted return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } .... }//HttpServiceMethod.java//CallAdapted 是 HttpServiceMethod 的內部類也是 HttpServiceMethod 的子類CallAdapted( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) { //這裡把 requestFactory 傳給 super 父類的構造引數裡了,也就是 HttpServiceMethod super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter; }//HttpServiceMethod.javaHttpServiceMethod( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter) { // HttpServiceMethod 的 requestFactory 成員變數儲存這個 RequestFactory 物件 this.requestFactory = requestFactory; this.callFactory = callFactory; this.responseConverter = responseConverter; }//因為會呼叫 HttpServiceMethod 的 invoke 方法//會把這個 RequestFactory 物件會繼續傳遞給 OkHttpCall 類中//注意換類了//OkHttpCall.javaOkHttpCall( RequestFactory requestFactory, Object[] args, okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) { //給 OkHttpCall 的requestFactory成員變數賦值 this.requestFactory = requestFactory; this.args = args; this.callFactory = callFactory; this.responseConverter = responseConverter; } 複製程式碼
經過層層傳遞 RequestFactory 這個例項終於是到了 HttpServiceMethod 類中,最終傳到了 OkHttpCall 中,那這個 RequestFactory 物件在什麼時候使用呢? RequestFactory 會繼續在OkHttpCall中傳遞,因為 OkHttpCall 才是進行請求的。
在OkHttpCall的 建立 Call 物件時
//OkHttpCall.javaprivate okhttp3.Call createRawCall() throws IOException { //1 okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; } 複製程式碼
註釋 1:呼叫了
requestFactory.create(args)
注意:此時的RequestFactory的各個成員變數在解析註解那一步都賦值了
//RequestFactory.javaokhttp3.Request create(Object[] args) throws IOException { ... RequestBuilder requestBuilder = new RequestBuilder( httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart); ... return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build(); } 複製程式碼
最終 requestFactory 的值用來構造 okhttp3.Request 的物件
以上就是解析註解,構造出okhttp3.Request的物件全過程了。
也就解答了 方法上的註解是什麼時候解析的,怎麼解析的?這個問題
8.4.請求響應結果是如何解析的
比如我們在構造 Retrofit 的時候加上
addConverterFactory(GsonConverterFactory.create())
這行程式碼,我們的響應結果是如何透過 Gson 直接解析成資料模型的?
在 OkHttpCall 的
enqueue
方法中
//OkHttpCall.java@Overridepublic void enqueue(final Callback<T> callback) { okhttp3.Call call; ... call.enqueue( new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { //1 解析響應 response = parseResponse(rawResponse); } catch (Throwable e) { throwIfFatal(e); callFailure(e); return; } } ... }); } 複製程式碼
註釋 1:透過
parseResponse
解析響應返回給回撥介面
//OkHttpCall.javaprivate final Converter<ResponseBody, T> responseConverter;Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); ... ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody); try { //1 透過 responseConverter 轉換 ResponseBody T body = responseConverter.convert(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { // If the underlying source threw an exception, propagate that rather than indicating it was // a runtime exception. catchingBody.throwIfCaught(); throw e; } } 複製程式碼
註釋 1:透過 responseConverter 呼叫
convert
方法
首先那看 responseConverter 是什麼以及賦值的過程,然後再看
convert
方法
//OkHttpCall.javaprivate final Converter<ResponseBody, T> responseConverter; OkHttpCall( RequestFactory requestFactory, Object[] args, okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) { this.requestFactory = requestFactory; this.args = args; this.callFactory = callFactory; //在構造中賦值 this.responseConverter = responseConverter; }// OkHttpCall 在 HttpServiceMethod 類中例項化//注意換類了//HttpServiceMethod.javaprivate final Converter<ResponseBody, ResponseT> responseConverter; HttpServiceMethod( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter) { this.requestFactory = requestFactory; this.callFactory = callFactory; //在構造中賦值 this.responseConverter = responseConverter; }//HttpServiceMethod 在子類 CallAdapted 呼叫 super方法賦值CallAdapted( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) { //在CallAdapted中呼叫super賦值 super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter; } 複製程式碼
繼續看 CallAdapted 的初始化中 responseConverter 的賦值過程
//HttpServiceMethod.javastatic <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { ... CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); //1 例項化responseConverter Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { //2 CallAdapted的例項化賦值 return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } ... } 複製程式碼
繼續跟程式碼
createResponseConverter
方法
//HttpServiceMethod.javaprivate static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter( Retrofit retrofit, Method method, Type responseType) { Annotation[] annotations = method.getAnnotations(); try { //呼叫的是 retrofit的方法 return retrofit.responseBodyConverter(responseType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(method, e, "Unable to create converter for %s", responseType); } }//注意換類了//Retrofit.javafinal List<Converter.Factory> converterFactories;public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) { //繼續跟 nextResponseBodyConverter return nextResponseBodyConverter(null, type, annotations); }public <T> Converter<ResponseBody, T> nextResponseBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) { ... //1 從 converterFactories工廠中遍歷取出 int start = converterFactories.indexOf(skipPast) + 1; for (int i = start, count = converterFactories.size(); i < count; i++) { Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this); if (converter != null) { //noinspection unchecked return (Converter<ResponseBody, T>) converter; } } ... } 複製程式碼
註釋 1:從 converterFactories 遍歷取出一個來呼叫
responseBodyConverter
方法,注意根據 responseType
返回值型別來取到對應的 Converter,如果不為空,直接返回此 Converter 物件
看一下 converterFactories 這個物件的賦值過程
//Retrofit.javafinal List<Converter.Factory> converterFactories; Retrofit( okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories, @Nullable Executor callbackExecutor, boolean validateEagerly) { this.callFactory = callFactory; this.baseUrl = baseUrl; this.converterFactories = converterFactories; // Copy+unmodifiable at call site. //透過 Retrofit 的構造賦值,Retrofit的 初始化是透過內部 Builder 類的build方法 this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site. this.callbackExecutor = callbackExecutor; this.validateEagerly = validateEagerly; }//Retrofit.java 內部類 Builder 類的build方法//Builder.java public Retrofit build() { ... // Make a defensive copy of the converters. //1 List<Converter.Factory> converterFactories = new ArrayList<>( 1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize()); //2 converterFactories.add(new BuiltInConverters()); //3 converterFactories.addAll(this.converterFactories); //4 converterFactories.addAll(platform.defaultConverterFactories()); return new Retrofit( callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); } 複製程式碼
註釋 1:初始化 converterFactories 這個 list
註釋 2:新增預設的構建的轉換器,其實是 StreamingResponseBodyConverter 和 BufferingResponseBodyConverter
註釋 3:就是自己新增的轉換配置
addConverterFactory(GsonConverterFactory.create())
//Retrofit.java 內部類 Builder.javapublic Builder addConverterFactory(Converter.Factory factory) { converterFactories.add(Objects.requireNonNull(factory, "factory == null")); return this; } 複製程式碼
註釋 4:如果是 Java8 就是一個 OptionalConverterFactory 的轉換器否則就是一個空的
注意:是怎麼找到GsonConverterFactory來呼叫 Gson 的 convert方法的呢?在遍歷converterFactories時會根據 responseType來找到對應的轉換器。
具體 GsonConverterFactory 的
convert
方法就是 Gson 的邏輯了,就不是 Retrofit 的重點了。
到現在 Converter 的轉換過程,我們也就清楚了。
還有一個問題,我們寫的 API 介面是如何支援 RxJava 的
9.CallAdapter的替換過程
9.1.使用 RxJava 進行網路請求
怎麼轉成 RxJava
比如:我們在初始化一個Retrofit時加入
addCallAdapterFactory(RxJava2CallAdapterFactory.create())
這行
//初始化一個Retrofit物件val retrofit = Retrofit.Builder() .baseUrl(") //加入 RxJava2CallAdapterFactory 支援 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build() 複製程式碼
加入 RxJava2 的配置支援後,把 RxJava2CallAdapterFactory 存到 callAdapterFactories 這個集合中,記住這一點,下面要用到。
interface GitHubApiService { @GET("users/{user}/repos") fun listReposRx(@Path("user") user: String?): Single<Repo> } 複製程式碼
我們就可以這麼請求介面了
//建立出GitHubApiService物件val service = retrofit.create(GitHubApiService::class.java) service.listReposRx("octocat") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ repo -> "response name = ${repo[0].name}".logE() }, { error -> error.printStackTrace() }) 複製程式碼
我們可以在自己定義的 API 介面中直接返回一個 RxJava 的 Single 物件的,來進行操作了。
我們下面就來看下是如何把請求物件轉換成一個 Single 物件的
//Retrofit.java 內部類 Builder.javapublic Builder addCallAdapterFactory(CallAdapter.Factory factory) { callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null")); return this; } 複製程式碼
把 RxJava2CallAdapterFactory 存到了callAdapterFactories 這個 list 中了。
接下來我們看下是如何使用 callAdapterFactories 的 RxJava2CallAdapterFactory 中的這個 CallAdapter 的吧
這就要看我們之前看到了一個類了 HttpServiceMethod 的
parseAnnotations
之前看過它的程式碼,只是上次看的是
Converter是如何賦值的也就是第 8.4 小節,這次看 CallAdapter 是如何被賦值使用的。
9.2CallAdapter是如何被賦值過程
HttpServiceMethod的
parseAnnotations
方法
//HttpServiceMethod.javastatic <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { .... //1 CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { //2 return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } ... } 複製程式碼
註釋 1:初始化 CallAdapter
註釋 2:給
CallAdapted 中的 callAdapter 變數賦值,然後呼叫它的
adapt
方法。
我們先找到具體 CallAdapter 賦值的物件,然後看它的
adapt
就知道了,是如何轉換的了
接下來就是跟程式碼的過程了
//HttpServiceMethod.javaprivate static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter( Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) { try { //noinspection unchecked //呼叫retrofit的callAdapter方法 return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(method, e, "Unable to create call adapter for %s", returnType); } }//Retrofit.javapublic CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { //呼叫nextCallAdapter return nextCallAdapter(null, returnType, annotations); }public CallAdapter<?, ?> nextCallAdapter( @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { ... //遍歷 callAdapterFactories int start = callAdapterFactories.indexOf(skipPast) + 1; for (int i = start, count = callAdapterFactories.size(); i < count; i++) { //是具體CallAdapterFactory的 get 方法 CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } ... } 複製程式碼
遍歷 callAdapterFactories 根據 returnType型別 來找到對應的 CallAdapter 返回
比如:我們在 GitHubApiService 的 returnType 型別為 Single,那麼返回的就是 RxJava2CallAdapterFactory 所獲取的 CallAdapter
interface GitHubApiService { @GET("users/{user}/repos") fun listReposRx(@Path("user") user: String?): Single<Repo> } 複製程式碼
RxJava2CallAdapterFactory的
get
方法
//RxJava2CallAdapterFactory.java@Override public @Nullable CallAdapter<?, ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { Class<?> rawType = getRawType(returnType); if (rawType == Completable.class) { return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false, false, true); } boolean isFlowable = rawType == Flowable.class; //當前是Single型別 boolean isSingle = rawType == Single.class; boolean isMaybe = rawType == Maybe.class; if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) { return null; } ... //返回 RxJava2CallAdapter物件,isSingle引數為 true return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable, isSingle, isMaybe, false); } 複製程式碼
返回的是 RxJava2CallAdapter 物件,並且根據 rawType 判斷當前是個什麼型別
看下 RxJava2CallAdapter 的
adapt
方法
//RxJava2CallAdapter.java@Override public Object adapt(Call<R> call) { //1 把Call包裝成一個Observable物件 Observable<Response<R>> responseObservable = isAsync ? new CallEnqueueObservable<>(call) : new CallExecuteObservable<>(call); Observable<?> observable; if (isResult) { observable = new ResultObservable<>(responseObservable); } else if (isBody) { observable = new BodyObservable<>(responseObservable); } else { observable = responseObservable; } if (scheduler != null) { observable = observable.subscribeOn(scheduler); } if (isFlowable) { return observable.toFlowable(BackpressureStrategy.LATEST); } //2 if (isSingle) { return observable.singleOrError(); } if (isMaybe) { return observable.singleElement(); } if (isCompletable) { return observable.ignoreElements(); } return RxJavaPlugins.onAssembly(observable); } 複製程式碼
註釋 1:把 Call 包裝成一個 Observable 物件
註釋2:如果是 Single 則呼叫
observable.singleOrError();
方法
到目前為止, CallAdapter 怎麼變成一個 RxJava2CallAdapter 以及它的具體呼叫,我們也就清楚了。
10.Retrofit 如何支援 Kotlin 協程的 suspend 掛起函式的?
整個流程中還有一點我們沒有分析 Retrofit 如何支援 Kotlin 協程的 suspend 掛起函式的?
首先寫一個 Demo 來看一下協程是怎麼進行網路請求的
10.1.Kotlin 協程請求網路的 Demo
新增依賴
def kotlin_coroutines = '1.3.7'implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines"implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines"implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'複製程式碼
定義請求介面,寫一個掛起函式
interface GitHubApiService { //使用 Kotlin 協程 ,定義一個掛起函式 @GET("users/{user}/repos") suspend fun listReposKt(@Path("user") user: String?): List<Repo> } 複製程式碼
請求介面
//建立出GitHubApiService物件val service = retrofit.create(GitHubApiService::class.java)//lifecycle提供的協程的Scope,因為 suspend 函式需要執行在協程裡面lifecycleScope.launchWhenResumed { try { val repo = service.listReposKt("octocat") "response name = ${repo[0].name}".logE() } catch (e: Exception) { e.printStackTrace() //出錯邏輯 //ignore } } 複製程式碼
以上就是一個,用 Kotlin 協程進行網路請求的,Retrofit 是支援 Kotlin 協程的,接下來看下,Retrofit 是怎麼支援的。
10.2.分析Kotlin 協程的掛起函式的準備工作
首先在開始之前,我們得先得從程式碼角度知道,Kotlin 的 suspend 函式對應的 Java 類是什麼樣子,不然,就一個 suspend 關鍵字根本就沒法進行分析。
我寫一個 suspend 的測試方法,然後轉換成 java 方法看一下,這個 suspend 函式是個啥。
寫一個 Top Level 的Suspend.kt檔案(在文章最後我會給出原始碼,一看就明白)
在檔案中寫了一個測試的 suspend 函式
suspend fun test(name: String) { } 複製程式碼
我們透過 Android Studio 再帶的工具,如下圖:把 Kotlin 方法轉成 Java 方法
點這個按鈕
結果如下
public final class SuspendKt { @Nullable public static final Object test(@NotNull String name, @NotNull Continuation $completion) { return Unit.INSTANCE; } } 複製程式碼
看到了,我們的 suspend 的關鍵字,變成了
test
方法的一個Continuation引數,且為最後一個引數
看一下這個 Continuation類, 記住這個類,下面在分析的時候會遇到
@SinceKotlin("1.3")public interface Continuation<in T> { public val context: CoroutineContext public fun resumeWith(result: Result<T>)} 複製程式碼
好目前的準備工作都已經完成,開始分析 Retrofit 是怎麼支援 Kotlin 協程的掛起函式的。
10.3.Retrofit 是怎麼支援 Kotlin 協程的掛起函式的。
經過前面的原始碼解讀,我們知道,最終會呼叫到 HttpServiceMethod 的
parseAnnotations
方法
10.3.1.我們再看下這個方法,這次只看有關 協程的部分
//HttpServiceMethod.javastatic <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { //1 獲取 isKotlinSuspendFunction 的值,這個會在下面具體分析 boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; boolean continuationWantsResponse = false; boolean continuationBodyNullable = false; Annotation[] annotations = method.getAnnotations(); Type adapterType; //2 如果是 Kotlin 掛起函式 if (isKotlinSuspendFunction) { Type[] parameterTypes = method.getGenericParameterTypes(); Type responseType = Utils.getParameterLowerBound( 0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]); if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) { responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType); //3 continuationWantsResponse 賦值為 true continuationWantsResponse = true; } else { } adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType); annotations = SkipCallbackExecutorImpl.ensurePresent(annotations); } else { adapterType = method.getGenericReturnType(); } Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } else if (continuationWantsResponse) { //4 返回 SuspendForResponse 它是 HttpServiceMethod的子類 return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter); } else { return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter, continuationBodyNullable); } } 複製程式碼
註釋 1:獲取 isKotlinSuspendFunction 的值,這個會在下面具體分析
註釋 2:如果是 Kotlin 掛起函式,進入此程式碼塊
註釋 3:把 continuationWantsResponse 賦值為 true
註釋 4:返回 SuspendForResponse 它是 HttpServiceMethod 的子類,然後看它的
adapt
方法,這個會在下面具體分析
獲取 isKotlinSuspendFunction 的值的過程
10.3.2.看 requestFactory 的 isKotlinSuspendFunction 賦值
requestFactory 這個類,我們之前分析過,就是解析註解的,但是有一部分沒看,就是解析方法引數上的註解,這次就看下。
//RequestFactory.javaprivate @Nullable ParameterHandler<?> parseParameter( int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) { ParameterHandler<?> result = null; if (annotations != null) { for (Annotation annotation : annotations) { ParameterHandler<?> annotationAction = //1 遍歷解析引數的註解,就是 @Path @Query @Field 等註解,具體就不看了,不是協程的重點 parseParameterAnnotation(p, parameterType, annotations, annotation); if (annotationAction == null) { continue; } if (result != null) { throw parameterError( method, p, "Multiple Retrofit annotations found, only one allowed."); } result = annotationAction; } } if (result == null) { //2 如果是協程 ,其實比的就是最後一個值 if (allowContinuation) { try { //3 判斷引數型別是 Continuation,這個介面,前面在 10.2 小節寫 Demo 時提過 if (Utils.getRawType(parameterType) == Continuation.class) { // 4 isKotlinSuspendFunction 賦值為 true isKotlinSuspendFunction = true; return null; } } catch (NoClassDefFoundError ignored) { } } throw parameterError(method, p, "No Retrofit annotation found."); } return result; } 複製程式碼
註釋 1:遍歷解析引數的註解,就是 @Path @Query @Field 等註解,具體就不看了,不是協程的重點
註釋 2:如果是協程 ,其實比的就是最後一個值
註釋 3:判斷引數型別是 Continuation,這個介面,前面在 10.2 小節寫 Demo 時提過
註釋 4:isKotlinSuspendFunction 賦值為 true
如果isKotlinSuspendFunction 為 true 時,返回就是 SuspendForResponse 類
接下來就要 SuspendForResponse 以及它的
adapt
方法了
10.3.3.看一下SuspendForResponse類
static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> { private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter; SuspendForResponse( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, Call<ResponseT>> callAdapter) { super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter; } @Override protected Object adapt(Call<ResponseT> call, Object[] args) { //1 call = callAdapter.adapt(call); //noinspection unchecked Checked by reflection inside RequestFactory. //2 Continuation<Response<ResponseT>> continuation = (Continuation<Response<ResponseT>>) args[args.length - 1]; // See SuspendForBody for explanation about this try/catch. try { //3 return KotlinExtensions.awaitResponse(call, continuation); } catch (Exception e) { //4 return KotlinExtensions.suspendAndThrow(e, continuation); } } } 複製程式碼
註釋 1:呼叫 callAdapter 代理 call 方法
註釋 2:取出最後一個引數,強轉成 Continuation 型別,想想我們寫的 Demo
註釋 3:Call 的擴充套件函式(Kotlin 的寫法)下面具體看下
awaitResponse
註釋 4:出現異常,丟擲異常。所以我們要在程式碼中,要主動 try catch,來處理錯誤
10.3.4.看一下Call的擴充套件函式
//KotlinExtensions.ktsuspend fun <T> Call<T>.awaitResponse(): Response<T> { return suspendCancellableCoroutine { continuation -> continuation.invokeOnCancellation { cancel() } //呼叫 Call的enqueue方法 enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { //成功回撥 continuation.resume(response) } override fun onFailure(call: Call<T>, t: Throwable) { //失敗回撥 continuation.resumeWithException(t) } }) } } 複製程式碼
到現在,整個用 Kotlin 協程的請求過程我們也就看完了。
11.總結
至此,整個 Retrofit 的整體流程就分析完了,具體細節還需要好好研究,我們再總結一下,回答開始的問題
11.1.什麼是動態代理?
分兩點
動態指的是在執行期,而代理指的是實現了某個介面的具體類,稱之為代理,會呼叫了 InvocationHandler 的
invoke
方法。
Retrofit 中的動態代理:
- 在程式碼執行中,會動態建立 GitHubApiService 介面的實現類,作為代理物件,代理介面的方法
- 在我們呼叫GitHubApiService 介面的實現類的
listRepos
方法時,會呼叫了 InvocationHandler 的invoke
方法。 - 本質上是在執行期,生成了 GitHubApiService 介面的實現類,呼叫了 InvocationHandler 的
invoke
方法。
具體看第 6 節
11.2.整個請求的流程是怎樣的
- 我們在呼叫 GitHubApiService 介面的
listRepos
方法時,會呼叫 InvocationHandler 的invoke
方法 - 然後執行
loadServiceMethod
方法並返回一個 HttpServiceMethod 物件並呼叫它的invoke
方法 - 然後執行 OkHttpCall的
enqueue
方法 - 本質執行的是 okhttp3.Call 的
enqueue
方法 - 當然這期間會解析方法上的註解,方法的引數註解,拼成 okhttp3.Call 需要的 okhttp3.Request 物件
- 然後透過 Converter 來解析返回的響應資料,並回撥 CallBack 介面
以上就是這個Retrofit 的請求流程
11.3.底層是如何用 OkHttp 請求的?
看下第 11.2小節的解釋吧
具體看第 8 節
11.4.方法上的註解是什麼時候解析的,怎麼解析的?
- 在 ServiceMethod.parseAnnotations(this, method); 方法中開始的
- 具體內容是在 RequestFactory 類中,進行解析註解的
- 呼叫 RequestFactory.parseAnnotations(retrofit, method); 方法實現的
具體看第 8.2 小節
11.5.Converter 的轉換過程,怎麼透過 Gson 轉成對應的資料模型的?
- 透過成功回撥的
parseResponse(rawResponse);
方法開始 - 透過 responseConverter 的
convert
方法 - responseConverter 是透過 converterFactories 透過遍歷,根據返回值型別來使用對應的 Converter 解析
具體看第 8.4 小節
11.6.CallAdapter 的替換過程,怎麼轉成 RxJava 進行操作的?
- 透過配置 addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 在 callAdapterFactories 這個 list 中新增 RxJava2CallAdapterFactory
- 如果不是 Kotlin 掛起函式最終呼叫的是 CallAdapted 的
adapt
方法 - callAdapter 的例項是透過 callAdapterFactories 這個 list 透過遍歷,根據返回值型別來選擇合適的CallAdapter
具體看第 9 節
11.7.如何支援 Kotlin 協程的 suspend 掛起函式的?
- 透過 RequestFactory 解析方法上的引數值來判斷是不是一個掛起函式,並把 isKotlinSuspendFunction 變數置為 true
- 根據 isKotlinSuspendFunction 這個變數來判斷響應型別是否是 Response 型別,然後把continuationWantsResponse 置為 true
- 根據 continuationWantsResponse 這個變數,來返回 SuspendForResponse 物件
- 並呼叫 SuspendForResponse 的 invoke 方法
- 透過 Call 的擴充套件函式,來呼叫 Call 的 enqueue方法
- 透過協程來返回
具體看第 10 節
到此為止,這篇文章算寫完了,當然還有很多具體細節沒有研究,但對 Retrofit 的各個方面都進行了閱讀。
Android Retrofit原始碼解析 ——→
影片地址
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69983917/viewspace-2803041/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android Retrofit原始碼解析Android原始碼
- [Android] Retrofit原始碼:流程解析Android原始碼
- Android 網路框架 Retrofit 原始碼解析Android框架原始碼
- RxJava + Retrofit原始碼解析RxJava原始碼
- Android進階必學retrofit原始碼解析Android原始碼
- Android Retrofit 2.5.0使用基礎詳解Android
- Android網路程式設計:Retrofit原始碼解析Android程式設計原始碼
- Android技能樹 — 網路小結(7)之 Retrofit原始碼詳細解析Android原始碼
- Retrofit2原始碼解析(一)原始碼
- 【原始碼SOLO】Retrofit2原始碼解析(一)原始碼
- Retrofit網路請求原始碼解析原始碼
- retrofit 原始碼分析原始碼
- Retrofit原始碼分析原始碼
- Retrofit 原始碼學習與使用原始碼
- Retrofit原始碼解析之網路請求原始碼
- Android中Retrofit的封裝使用Android封裝
- Android:這是一份全面 & 詳細的Retrofit 2.0 原始碼分析指南Android原始碼
- Retrofit原始碼分析三 原始碼分析原始碼
- Retrofit2.0- 原始碼分析原始碼
- Android:Retrofit 2.0 使用攻略(含例項講解)Android
- 原始碼分析Retrofit請求流程原始碼
- Retrofit原始碼學習筆記原始碼筆記
- Retrofit原始碼分析二 代理模式原始碼模式
- Retrofit原始碼分析一 概覽原始碼
- Android主流三方庫原始碼分析(二、深入理解Retrofit原始碼)Android原始碼
- Retrofit基本使用
- Retrofit 2.0 使用教程
- Android進階:七、Retrofit2.0原理解析之最簡流程Android
- spring-cloud-square原始碼速讀(retrofit + okhttp篇)SpringCloud原始碼HTTP
- 輕鬆搞定Retrofit不同網路請求方式的請求引數配置,Retrofit常用註解的使用
- Retrofit + RxJavaRxJava
- Android進階:七、Retrofit2.0原理解析之最簡流程【上】Android
- Android RxJava系列三: 與Retrofit2結合使用和封AndroidRxJava
- Retrofit流水賬
- Retrofit2+RxJava 簡單使用RxJava
- 配置Retrofit網路框架及其使用框架
- Retrofit使用方法全面總結
- Android使用Kotlin+Retrofit+Rxjava實現簡單的網路請求AndroidKotlinRxJava