你在使用 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("https://api.github.com/")
.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.java
public <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.$Proxy0
method = 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.java
public <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.java
private 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.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
...
//1
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
復制代碼
返回的是一個HttpServiceMethod對象,那么接下來看下它的 invoke 方法
7.3.HttpServiceMethod 的 invoke 方法
//HttpServiceMethod.java
@Override
final @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
@Override
public 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.java
private 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.java
OkHttpCall(
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.java
private final okhttp3.Call.Factory callFactory;
@Override
final @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.java
static <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.java
public 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.java
static <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.java
final 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.java
private 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.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//解析注解參數,獲取 RequestFactory 對象
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
//把 RequestFactory 對象傳給 HttpServiceMethod
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
//注意換類了
//HttpServiceMethod.java
static <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.java
HttpServiceMethod(
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.java
OkHttpCall(
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.java
private 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.java
okhttp3.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
@Override
public 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.java
private 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.java
private 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.java
private 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.java
static <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.java
private 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.java
final 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.java
final 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.java
public 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("https://api.github.com/")
//加入 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.java
public 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.java
static <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.java
private 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.java
public 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.java
static <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.java
private @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.kt
suspend 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源碼解析 ——→視頻地址
作者:AboBack
鏈接:https://juejin.cn/post/6869584323079569415
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。