一、概述
Retrofit 是一個(gè)基于 OkHttp ,并遵循 Restful 風(fēng)格的一個(gè)網(wǎng)絡(luò)請(qǐng)求封裝庫,它將一個(gè)請(qǐng)求以接口的形式具現(xiàn)化的表現(xiàn)出來,將 OkHttp 的請(qǐng)求操作簡(jiǎn)化,并可以配置 convert 將響應(yīng)轉(zhuǎn)換為你想要的數(shù)據(jù) model,且支持異步或同步的操作,2.6.x 版本以上更是對(duì)協(xié)程進(jìn)行了支持,其優(yōu)異的設(shè)計(jì),簡(jiǎn)便的請(qǐng)求方式,推出沒多久就在 Android 開發(fā)領(lǐng)域出圈,目前 github star 數(shù)量已經(jīng)達(dá)到 37.8k 并被大量的 App 采用。
現(xiàn)如今更是成為各大公司面試的長(zhǎng)問問題?;诖耍酒恼聲?huì)從源碼層面深入分析 Retrofit 的運(yùn)行機(jī)制,了解 Retrofit 的內(nèi)部原理。
站在巨人的肩膀上眺望,就算最終我們成不了巨人,起碼也能比旁人看的更遠(yuǎn)不是。
二、Retrofit 基本流程圖
如圖所示,接下來我們就按照流程圖來逐步分析 Retrofit 的源碼
三、一個(gè)簡(jiǎn)單的請(qǐng)求
閱讀源碼的最好方式就是從使用的角度從調(diào)用鏈一步步深入分析,這樣能讓我們避免在繁復(fù)紛雜的代碼中迷失方向,無所適從。所以讓我們從一個(gè)簡(jiǎn)單的請(qǐng)求開始,慢慢的揭開 Retrofit 神秘的面紗。
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
}
public static final String API_URL = "https://api.github.com";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// Create an instance of our GitHub API interface.
GitHub github = retrofit.create(GitHub.class);
// Create a call instance for looking up Retrofit contributors.
Call<List<Contributor>> call = github.contributors("square", "retrofit");
// Fetch and print a list of the contributors to the library.
List<Contributor> contributors = call.execute().body();
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
上述代碼是 Retrofit 官方 sample 中的例子,代碼并不是很多,可以看到經(jīng)過一些耳熟能詳?shù)臉?gòu)建步驟和一個(gè)聲明的 Restful 接口,就獲得了一個(gè)可以進(jìn)行 enqueue/sync 請(qǐng)求的 Call 對(duì)象,而通過這個(gè) Call 對(duì)象我們就可以直接獲取我們想要的 Response, 不得不佩服,真的是將網(wǎng)絡(luò)請(qǐng)求變得非常簡(jiǎn)便。
這里我特別說明一下 build 的構(gòu)建過程,有助于后面文章的理解
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//第一步創(chuàng)建一個(gè) OkHttpClient 對(duì)象
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//第二步創(chuàng)建一個(gè)回調(diào)線程 ,Platform 是在 Builder 構(gòu)造方法中進(jìn)行的實(shí)例化并傳入
//主要作用判斷當(dāng)前的運(yùn)行環(huán)境,如果是 Android 則返回 AndroidCallback
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 第三步將所有的 CallAdapter add 到 callAdapterFactories 集合中
//例如常用的 RxJavaCallAdapterFactory
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// 第四步將所有的 Converter add 到 converterFactories 集合中
//列如我們常用的 GsonConvertFactory
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
//添加 Retrofit 默認(rèn)提供的 converter ,當(dāng)我們的返回類型為 Call<ResponseBody> 就會(huì)使用這個(gè) BuiltInConverters
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
//創(chuàng)建 Retrofit 實(shí)例
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
說實(shí)話,前幾年第一次看到這種網(wǎng)絡(luò)請(qǐng)求的方式的時(shí)候,感覺還是蠻秀的,竟然還能這么玩? 在使用了一段時(shí)間后,非常好奇它是怎做到的,相信有不少童鞋應(yīng)該也很好奇吧。接下來我們慢慢看看這么神奇的操作是怎么完成的~
四、Retrofit 的 create 方法
在進(jìn)行分析之前,如果你對(duì) Java 動(dòng)態(tài)代理、反射、注解沒什么了解的話,建議先簡(jiǎn)單的了解一下,否則可能無法愉快的閱讀后續(xù)的文章。
public <T> T create(final Class<T> service) {
//校驗(yàn)接口是否可用
validateServiceInterface(service);
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 {
// 調(diào)用的是成員類方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//調(diào)用的是 Object 的默認(rèn)方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//將解析的請(qǐng)求組裝成一個(gè) Call 對(duì)象返回
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
create 方法接收一個(gè) Class<T> 類型的形參,內(nèi)部通過動(dòng)態(tài)代理的方式,在運(yùn)行時(shí)創(chuàng)建了 Github Api 的接口實(shí)現(xiàn)類,在調(diào)用接口方法時(shí),代理類會(huì)執(zhí)行 InvocationHandler 的 invoke 方法,而在 invoke 方法中我們就可以對(duì) Github 接口中聲明的方法進(jìn)行一些我們想做的改動(dòng)了。
可能說到這里,還是有點(diǎn)繞,其實(shí)簡(jiǎn)而言之,這個(gè) invoke 方法有點(diǎn)相當(dāng)一個(gè)方法攔截器,可以在調(diào)用實(shí)際的方法前植入一些前期操作,比如當(dāng)我們調(diào)用下面的代碼時(shí)
Call<List<Contributor>> call = github.contributors("square", "retrofit");
此時(shí)在執(zhí)行 contributors 方法時(shí),會(huì)先調(diào)用 InvocationHandler 的 invoke方法,在這個(gè)方法中,Retrofit 會(huì)對(duì)方法中的注解通過反射進(jìn)行解析,其中會(huì)解析形參類型,返回類型等等,并將其組裝成一個(gè) Call 對(duì)象返回。其實(shí)如果你對(duì) Java 的 AOP 有過了解的話,那么這里的思想也是一樣的。
動(dòng)態(tài)代理相關(guān)內(nèi)容就先解釋到這里,接下來我們來重點(diǎn)看看 loadServiceMethod 方法
ServiceMethod<?> loadServiceMethod(Method method) {
//檢查緩存中是否有可用的接口方法
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//解析接口方法中注解
result = ServiceMethod.parseAnnotations(this, method);
//加入緩存
serviceMethodCache.put(method, result);
}
}
return result;
}
loadServiceMethod 做的事情并不復(fù)雜,就是判斷方法簽名是否緩存過,沒有則解析方法中的所有注解,并加入緩存,代碼如下
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//解析接口方法中的所有注解并組裝成一個(gè)請(qǐng)求工廠
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
//獲取接口方法的返回類型
Type returnType = method.getGenericReturnType();
//省略一些判斷代碼...
//這里對(duì)各種參數(shù)進(jìn)行檢查,并拼裝成一個(gè) CallAdapted 對(duì)象
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
從上面的代碼中我們了解到,ServiceMethod 是一個(gè)抽象類,內(nèi)部聲明了一個(gè)靜態(tài)的泛型方法 parseAnnotations ,其中通過 RequestFactory 的靜態(tài) parseAnnotations 方法解析方法中的所有注解,通過 HttpServiceMethod 的靜態(tài) parseAnnotations 方法將解析的各種參數(shù)拼裝成一個(gè) CallAdapted 對(duì)象返回。
這里說明一下
HttpServiceMethod 也是個(gè)抽象類并繼承自 ServiceMethod 類且實(shí)現(xiàn)了 invoke 方法。
簡(jiǎn)單的了解了上面的代碼,接下來我們?cè)谥鹨豢纯?RequestFactory.parseAnnotations 和 HttpServiceMethod.parseAnnotations 為我們做了什么
五、Request 的參數(shù)解析過程
RequestFactory.parseAnnotations 方法在將 retrofit 對(duì)象和 method 傳入后,會(huì)創(chuàng)建一個(gè) Builder 對(duì)象,主要作用就是賦值,如下
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();//方法的注解數(shù)組
this.parameterTypes = method.getGenericParameterTypes();//形參的類型數(shù)組
this.parameterAnnotationsArray = method.getParameterAnnotations();//形參的注解數(shù)組
}
而具體的解析則在 build 方法中進(jìn)行,這里在特別說明一下,我們知道 Retrofit 主要通過注解來解釋一個(gè)接口信息,這里我將 Retrofit 常用的的注解分為兩大類,一種是針對(duì)方法修飾,一種是針對(duì)參數(shù)進(jìn)行修飾,具體信息如下
| method | parameter |
|---|---|
| GET | Url |
| POST | Path |
| HEAD | Query |
| PATCH | QueryName |
| PUT | QueryMap |
| OPTIONS | Header |
| HTTP | HeaderMap |
| Headers | Field |
| Multipart | FieldMap |
| FormUrlEncoded | Part |
| - | PartMap |
| - | Body |
| - | tag |
知道了區(qū)別,我們來看一下 RequestFactory 的結(jié)構(gòu)圖以及解析的流程圖。
可以看到解析的過程主要由兩個(gè)主要方法構(gòu)成,一個(gè)是 parseMethodAnnotation, 負(fù)責(zé)解析請(qǐng)求方法和 Header , 代碼很簡(jiǎn)單就不貼了,這里我們重點(diǎn)看一下 parseParameterAnnotation 方法,流程圖中寫的很清楚,它的主要作用就是將解析的形參注解生成一個(gè) ParameterHandler對(duì)象返回,那么這個(gè) ParameterHandler 能做些什么呢 ? 來看看它的結(jié)構(gòu)
可以看到 ParameterHandler 的子類共有 15 個(gè),且與上述的參數(shù)注解一一對(duì)應(yīng),其內(nèi)部有一個(gè)抽象方法 apply, 兩個(gè)默認(rèn)方法 iterable、array、其中前者主要解析的是集合數(shù)據(jù),后者主要針對(duì)數(shù)組的解析,但它們最終還是會(huì)調(diào)的是由各個(gè)子類實(shí)現(xiàn)的 apply 方法來將解析的鍵值對(duì)或 body 添加到我們的 request 中。
代碼形式如下
abstract class ParameterHandler<T> {
abstract void apply(RequestBuilder builder, @Nullable T value) throws IOException;
final ParameterHandler<Iterable<T>> iterable() {
return new ParameterHandler<Iterable<T>>() {
@Override void apply(RequestBuilder builder, @Nullable Iterable<T> values)
throws IOException {
if (values == null) return; // Skip null values.
for (T value : values) {
ParameterHandler.this.apply(builder, value);
}
}
};
}
final ParameterHandler<Object> array() {
return new ParameterHandler<Object>() {
@Override void apply(RequestBuilder builder, @Nullable Object values) throws IOException {
if (values == null) return; // Skip null values.
for (int i = 0, size = Array.getLength(values); i < size; i++) {
//noinspection unchecked
ParameterHandler.this.apply(builder, (T) Array.get(values, i));
}
}
};
}
其實(shí)關(guān)于解析的具體代碼大家稍微耐心看看就會(huì)明白,基本過程都相同,筆者在這里就不浪費(fèi)太多筆墨了。
六、Call 對(duì)象的誕生
當(dāng)我們調(diào)用 API 接口時(shí),會(huì)返回一個(gè) call 對(duì)象來讓我們進(jìn)行 async/enqueue 請(qǐng)求,而整個(gè) Call 對(duì)象的生成其實(shí)是一個(gè)挺復(fù)雜的過程,這里筆者會(huì)分三小節(jié)來詳細(xì)展開這個(gè)過程。
6.1、HttpServiceMethod.parseAnnotations 的作用
接口的方法注解和參數(shù)注解解析完成后,我們就獲得了一個(gè) RequestFactory 對(duì)象,這個(gè)對(duì)象包含我們請(qǐng)求的所有信息,那么接下來看看 HttpServiceMethod.parseAnnotations 方法幫我門做了什么
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
//獲取要適配的 call 類型
adapterType = method.getGenericReturnType();
//創(chuàng)建 call 適配器,這個(gè)適配器的主要作用就是為了獲取要返回的類型和要執(zhí)行的回調(diào)線程
//如果是協(xié)程則回調(diào)線程返回 null
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
//這里就是創(chuàng)建轉(zhuǎn)換器的地方,內(nèi)部會(huì)通過上面的獲取的 responseType 創(chuàng)建合適的轉(zhuǎn)換器
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
//獲取 OkHttpClient 實(shí)例
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
}
}
代碼做了精簡(jiǎn),刪除了 Kotlin 相關(guān)的部分,后面會(huì)單獨(dú)講,這里先主要講非 Kotlin 部分。
可以看到整個(gè)方法的作用就是為了返回一個(gè) CallAdapted 對(duì)象,而創(chuàng)建的過程由以下步驟完成
- method.getGenericReturnType(); 獲取我們聲明的返回類型 Call<T>
- createCallAdapter 創(chuàng)建一個(gè) Callback 線程
- createResponseConverter 創(chuàng)建 response 的 converter
- 獲取 Retrofit 初始化時(shí)創(chuàng)建的 OkHttpclient 對(duì)象
- 組裝成一個(gè) CallAdapted 對(duì)象返回
如果光看 CallAdapted 這個(gè)名字的話是很有迷惑性的,你可能覺得會(huì)和 CallAdapter 有關(guān)系,又或者覺得這可能就是 Call 對(duì)象,這里筆者先賣個(gè)關(guān)子,后面會(huì)深入剖析,大家先記住就行。
接下來我們深入了解 CallAdapter 和 Converter 的創(chuàng)建過程
6.1、CallAdapter 的創(chuàng)建
跟進(jìn)createCallAdapter 方法后會(huì)發(fā)現(xiàn)經(jīng)過層層調(diào)用,最終會(huì)進(jìn)入到 Retorift 的 nextCallAdapter 方法中進(jìn)行實(shí)際的創(chuàng)建過程
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
}
這是創(chuàng)建的 CallAdapter 的核心方法,代碼很簡(jiǎn)單就是開了個(gè)循環(huán),遍歷 callAdapterFactories 集合獲取合適的 callAdapter , (如果不知道 callAdapterFactories 集合從哪來的,請(qǐng)看第三節(jié)),如何才叫合適呢? 很簡(jiǎn)單就是根據(jù)我們的返回類型,對(duì)應(yīng)關(guān)系如下
| returnType | CallAdapter |
|---|---|
| Call.class | DefaultCallAdapterFactory |
| Observable.class | RxJavaCallAdapterFactory |
我們目前一直使用的返回類型是 Call.class 所以上述循環(huán)中調(diào)用的其實(shí)是DefaultCallAdapterFactory 的 get 方法
@Override public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
//非 Call 類型直接返回 null,遍歷下一個(gè)
if (getRawType(returnType) != Call.class) {
return null;
}
//必須為參數(shù)化類型,否則拋異常
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
//這里其實(shí)主要的作用是為了判斷是否使用了協(xié)程,如果實(shí)現(xiàn)了協(xié)程那么則不使用系統(tǒng)的回調(diào)線程并返回null
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
//創(chuàng)建一個(gè)匿名 CallAdapter 實(shí)例對(duì)象返回
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return executor == null
? call
: new ExecutorCallbackCall<>(executor, call);
}
};
}
get 方法的還是很簡(jiǎn)單的就是創(chuàng)建了一個(gè)匿名的 CallAdapter 類并返回,這里你需要的就是重點(diǎn)記一下 CallAdapter的adapt 方法,因?yàn)楹竺鏁?huì)調(diào)用到,至于 callbackExecutor 內(nèi)部則是通過 Handler 將我們的請(qǐng)求結(jié)果切換到主線程。你看下 Platform Android 環(huán)境下的 defaultCallbackExecutor 方法就明白了。至于 ExecutorCallbackCall 其實(shí)是真正執(zhí)行請(qǐng)求的類,這里大家先了解下,后面會(huì)講到
Retrofit 常用的 CallAdapter 整體的結(jié)構(gòu)圖如下
6.2、ResponseConverter 的創(chuàng)建
ResponseConverter 的調(diào)用過程可以說基本和 CallAdapter 的調(diào)用邏輯一模一樣,也是層層調(diào)用,最終進(jìn)入到 nextResponseBodyConverter 方法中
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
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;
}
}
}
和 callAdapter 的創(chuàng)建過程如出一轍,至于獲取什么類型的 converter 其實(shí)也有一個(gè)對(duì)應(yīng)關(guān)系
| returnType | converter |
|---|---|
| ResponseBody.class | BuiltInConverters |
| Model.class | GsonConverterFactory |
| Optional.class | OptionalConverterFactory |
顯然我們的例子只有 GsonConverterFactory 符合,所以進(jìn)入 responseBodyConverter 方法看看
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
代碼很簡(jiǎn)單就是通過 Gson 幫我們獲取要適配的返回類型,然后返回一個(gè) GsonResponseBodyConverter 對(duì)象,
而 GsonResponseBodyConverter 做的事情也很簡(jiǎn)單,通過重寫的 convert 方法將 RequestBody 中的流數(shù)據(jù)讀取并轉(zhuǎn)為我們的聲明的 model 類型,
代碼如下
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return result;
}
}
所以 GsonConverterFactory.responseBodyConverter 方法的主要作用就是幫我們創(chuàng)建了一個(gè) GsonResponseBodyConverter 對(duì)象來幫助我們完成 Response 的轉(zhuǎn)換
至此你應(yīng)該對(duì) Retrofit 的 Convert 工作流程有了一個(gè)比較清晰的了解,其實(shí) Retrofit 在構(gòu)建的時(shí)候內(nèi)部為我們提供了兩個(gè)默認(rèn)的 converter 分別是 BuiltInConverters 和 OptionalConverterFactory 后者只能在 Java8+ 或 Android API 24+ 環(huán)境中使用,且返回類型必須為 Optional.class 類型,感興趣的可以自己了解下,Android 基本用不到它。而前者則是通過 I/O 流 的方式將請(qǐng)求的信息和響應(yīng)信息包裝成一個(gè) RequestBody 和 ResponseBody ,所以當(dāng)你把返回類型設(shè)置為 Call<ResponseBody> 時(shí)也可以正常請(qǐng)求,但返回的是最原始的字節(jié)流。雖然每個(gè) Convert 的實(shí)現(xiàn)過程可能不盡相同,但基本的邏輯也是按照這個(gè)規(guī)律進(jìn)行的。
Retrofit 常用的 Converter 整體的結(jié)構(gòu)圖如下
6.3、 Call 對(duì)象的創(chuàng)建
經(jīng)過前面的分析,注解解析完了,OkHttpClient 對(duì)象有了,callAdapter 和 Converter 也創(chuàng)建了,至此終于滿足了創(chuàng)建 Call 對(duì)象的條件,但只是滿足了條件,此時(shí)還并未創(chuàng)建 Call 對(duì)象。而是將上述條件組裝成了一個(gè) CallAdapted 對(duì)象,看名字難道又是一個(gè) callAdapter 的子類? 可是我們前面不是已經(jīng)創(chuàng)建過了嗎?要想解除疑惑,讓我們看看 CallAdapted 的結(jié)構(gòu)圖就知道了
了解了 CallAdapted 的結(jié)構(gòu)關(guān)系,我們進(jìn)入代碼看看
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
//將解析的注解, OkHttpClient對(duì)象,以及創(chuàng)建的 call 和 converter 賦值給對(duì)應(yīng)的成員變量
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
可以看到 CallAdapted 作為 HttpServiceMethod 的子類,只重寫了 adapt 方法,并調(diào)用了 callAdapter 的 adapt 方法并返回了一個(gè) RetrunT 類型的對(duì)象,那么這個(gè) RetrunT 是啥呢?
讓我們回歸使用的起點(diǎn) ,發(fā)起一個(gè)請(qǐng)求
Call<List<Contributor>> call = github.contributors("square", "retrofit");
開頭已經(jīng)大致講述了動(dòng)態(tài)代理的基本作用,這里不再贅述。
此時(shí)整個(gè)調(diào)用過程如下,這里大家也可以跟進(jìn)代碼按照以下步驟跟進(jìn)調(diào)用鏈
- 通過動(dòng)態(tài)代理的方式調(diào)用 InvocationHandler 的 invoke 方法
- 在 invoke 方法中調(diào)用 loadServiceMethod 方法解析接口的注解,根據(jù)返回類型創(chuàng)建對(duì)應(yīng)的 callAdapter 和 convert,組裝成一個(gè) CallAdapted 返回
- 調(diào)用 CallAdapted 的 invoke 方法返回一個(gè) Call 對(duì)象
前面兩個(gè)步驟已經(jīng)做過詳細(xì)的分析,這里我們重點(diǎn)看下 invoke 方法。首先我們知道 CallAdapted 是 HttpServiceMethod 的子類,而 HttpServiceMethod 其實(shí)已經(jīng)實(shí)現(xiàn)了 invoke 方法,從前面的代碼中我們可以看到 CallAdapted 雖然只重寫了 adapt 方法,但根據(jù)繼承的特性 CallAdapted 自然也擁有了此方法。那么我們可以稍微改動(dòng)一下 CallAdpated 的代碼以方便大家理解
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
可以看到在 invoke 方法中創(chuàng)建了一個(gè) OkHttpCall 對(duì)象,并將我們請(qǐng)求的信息,參數(shù)(就是 contributors("square", "retrofit") ),OkHttpClient(就是 callFactory), 和 converter 傳入。并調(diào)用了 adapt 方法, adapt 方法中又調(diào)用了 callAdapter 的 adapt 方法并將 OkHttpCall 對(duì)象傳入并返回。這一系列的調(diào)用過程到底發(fā)生了什么呢?
首先看看 OkHttpCall 的類結(jié)構(gòu)圖
如圖所示 OkHttpCall 的主要作用就是為了幫我們進(jìn)行 async / enqueue 請(qǐng)求。
而 callAdapter.adapt 從前面的分析中它其實(shí)調(diào)用的是 DefaultCallAdapterFactory 的 get 方法為我們創(chuàng)建的一個(gè)匿名 CallAdapter 對(duì)象中實(shí)現(xiàn)的 adapt 方法,代碼如下
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final @Nullable Executor callbackExecutor;
@Override public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
//這里其實(shí)主要的作用是為了判斷是否使用了協(xié)程,如果實(shí)現(xiàn)了協(xié)程那么則不使用系統(tǒng)的回調(diào)線程并返回null
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor; // 內(nèi)部調(diào)用 handler 切換到主線程
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return executor == null
? call //OkHttoCall 對(duì)象
: new ExecutorCallbackCall<>(executor, call); // 新建一個(gè) Call 對(duì)象,并將 OkHttpCall 對(duì)象傳入
}
};
}
現(xiàn)在回過頭你可能就會(huì)明白我在 callAdapter 的創(chuàng)建那一節(jié)為什么要讓你重點(diǎn)關(guān)注 adapt 方法,因?yàn)?Call 對(duì)象就是在 adapt 方法中誕生的。而其中會(huì)涉及兩個(gè) Call 對(duì)象,一個(gè)是我們傳入的 OkHttpCall 另一個(gè)是 ExcutorCallBackCall 對(duì)象,而具體使用哪個(gè)則源于你是否用的是協(xié)程,如果是協(xié)程則直接用 OkHttpCall 否則創(chuàng)建一個(gè)新的 Call 對(duì)象。
那么此時(shí)再看這行代碼,相信你應(yīng)該知道我們的 Call 對(duì)象是如何誕生的吧,以及用的是哪個(gè) Call 對(duì)象了吧!
Call<List<Contributor>> call = github.contributors("square", "retrofit");
七、Call 對(duì)象的請(qǐng)求過程
讓我們先看一段 Retrofit 標(biāo)準(zhǔn)的請(qǐng)求過程
Call<List<Contributor>> call = github.contributors("square", "retrofit");
call.enqueue(new Callback<List<Contributor>>() {
@Override
public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}
@Override
public void onFailure(Call<List<Contributor>> call, Throwable t) {
}
});
經(jīng)過上一節(jié)的分析,我們知道了 Call 對(duì)象的誕生過程,也基本了解了 Call 的類結(jié)構(gòu),而在未使用協(xié)程的情況下我們使用的是新建的 ExecutorCallbackCall 對(duì)象,這個(gè) ExecutorCallbackCall 也實(shí)現(xiàn)了 Call 接口,所以它的結(jié)構(gòu)和 OkHttpCall 基本相同。讓我們看看它的 enqueue 方法
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;// 主線程的 Handler
this.delegate = delegate; // 傳入的 OkHttpCall
}
@Override public void enqueue(final Callback<T> callback) {
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(() -> {
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);
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
}
代碼的邏輯并不復(fù)雜,很有意思的是 ExecutorCallbackCall 的 enqueue 方法最終又委托 OkHttpCall 的 enqueue 方法來進(jìn)行真正的請(qǐng)求,同理 async 請(qǐng)求也是如此??磥頍o論套幾層殼子,最終的活還是由 OkHttpCall 來執(zhí)行啊。
OkHttpCall 將請(qǐng)求的 Response 返回后,在經(jīng)由 callbackExecuter 將結(jié)果切換到主線程處理,這里再?gòu)?qiáng)調(diào)一下 callbackExecuter 對(duì)象是在 Retrofit 在構(gòu)建時(shí)根據(jù)系統(tǒng)環(huán)境自動(dòng)創(chuàng)建的,如果是 Android 環(huán)境下調(diào)用 defaultCallbackExecutor 方法會(huì)返回一個(gè) MainThreadExecutor 對(duì)象,代碼如下
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
看來要想了解真正的請(qǐng)求過程,還是得進(jìn)入到 OkHttpCall 中的 enqueue 中查看
@Override public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
if (call == null && failure == null) {
call = rawCall = createRawCall();
}
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
response = parseResponse(rawResponse);
callback.onResponse(OkHttpCall.this, response);
}
代碼進(jìn)行了精簡(jiǎn),我們只看核心代碼,其實(shí)整個(gè) enqueue 方法總結(jié)起來干了這么幾件事
- createRawCall 創(chuàng)建一個(gè) OkHttp 原生的 Call 對(duì)象
- 通過 OkHttp 的 Call 對(duì)象發(fā)起一個(gè) 異步請(qǐng)求
- parseResponse 解析返回的 response
- callback.onResponse() 將解析的 response 回調(diào)給 ExecutorCallbackCall 的 enqueue 方法
那就簡(jiǎn)單了,接下來我們就按照這個(gè)步驟來看看,首先是 createRawCall 方法
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
return call;
}
原來是調(diào)用了 OkHttpClient 的 newCall 方法,而傳入的 request 是由 requestFactory 的 create 方法提供
okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // 參數(shù)處理對(duì)象數(shù)組
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;
//將接口注解解析的信息放入 RequestBuilder 中
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
if (isKotlinSuspendFunction) {
// The Continuation is the last parameter and the handlers array contains null at that index.
argumentCount--;
}
//遍歷參數(shù)處理對(duì)象數(shù)組,通過 Apply 方法添加進(jìn) requestBuilder
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);
}
//返回一個(gè) request 對(duì)象
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
}
獲取完 request 后,就可以直接創(chuàng)建一個(gè)OkHttp 的 Call 對(duì)象了,接下來就是解析 Call 對(duì)象請(qǐng)求后的響應(yīng)了,進(jìn)入 parseResponse 方法看看
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// 如果沒有響應(yīng)信息,這里創(chuàng)建一個(gè)沒有響應(yīng)體的原始 response 用于返回
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
// 省略一些判斷代碼
//創(chuàng)建一個(gè)用于捕獲在讀取響應(yīng)字節(jié)流過程發(fā)生 IO 異常的對(duì)象,內(nèi)部通過 Okio 讀取
//該對(duì)象集成自 ResponseBody
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//讀取正常,則通過 Converter 轉(zhuǎn)換我們的響應(yīng),并返回
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;
}
}
我們例子返回的是 Call.class 類型,所以這里的 responseConverter 對(duì)應(yīng)的其實(shí)是 GsonResponseBodyConverter,而具體的轉(zhuǎn)換過程也是由 GsonResponseBodyConverter 的 convert 方法處理,代碼如下
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;// Gson 對(duì)象
this.adapter = adapter;// model 的具體類型適配器
}
@Override public T convert(ResponseBody value) throws IOException {
//讀取 ResponseBoyd 的字符流并創(chuàng)建一個(gè) JsonReader 對(duì)象
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
//通過類型適配器讀取 jsonReader 并轉(zhuǎn)轉(zhuǎn)換為我們聲明的 model 類型
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return result;
} finally {
value.close();
}
}
}
解析完響應(yīng)返回后,最終調(diào)用 callback.onResponse 方法回調(diào)給 ExecutorCallbackCall ,在經(jīng)由 callbackExecutor 內(nèi)部的 handler 將 response 回調(diào)到主線程處理。
至此對(duì)于從 Retrofit 的構(gòu)建、到創(chuàng)建一個(gè) API 接口,以及發(fā)起一個(gè)請(qǐng)求的全部過程就分析完了。也完全對(duì)應(yīng)上了開頭的 Retorift 流程圖??v觀整個(gè)分析過程,真的感覺到設(shè)計(jì)這套框架的大佬的強(qiáng)大,能把各種設(shè)計(jì)模式,泛型、反射、注解靈活運(yùn)用成這個(gè)樣子,簡(jiǎn)直令人嘆服。真——五體投地,望塵莫及。
八、結(jié)語
限于篇幅,"Retrofit 源碼深入分析 —— Call 對(duì)象的誕生與請(qǐng)求" 就先分析到這里,如果想繼續(xù)了解 Retrofit 對(duì) RxJava 和 協(xié)程的支持,請(qǐng)看 Retrofit 源碼深入分析 —— RxJava 和 協(xié)程的支持