Retrofit 是目前作為網(wǎng)絡(luò)請求的主流框架,使用起來很方便,僅需在接口中定義方法踱卵,打上注解槐瑞,而且和 Rxjava 配合起來,可以更好的完成網(wǎng)絡(luò)請求時的線程切換問題崎页。那么這樣一個框架鞠绰,我們有必要對它的源碼分析一下,希望能夠從中吸取到一定的東西飒焦,Retrofit 框架里面用到了很設(shè)多計模式蜈膨,像外觀模式,代理模式牺荠,工廠模式翁巍,適配器模式,裝飾者模式等等休雌,這無疑是學(xué)習(xí)設(shè)計模式很好的一個實例灶壶。
如果對 Retrofit 的使用還不是很熟練的話,可以看看我之前寫的兩篇文章:
Retrofit2.0 學(xué)習(xí)第一彈——準備篇
Retrofit2.0 學(xué)習(xí)第二彈——使用篇
在看源碼之前杈曲,先來看幾個問題驰凛,帶著問題去看源碼,這樣更有目的性鱼蝉,不至于陷于源碼的細節(jié)而不能自拔洒嗤。
(1) 定義網(wǎng)絡(luò)請求是一個接口,里面的方法都是抽象方法魁亦,這些抽象方法是怎么被執(zhí)行的渔隶?
(2) 方法上的注解是如何被解析,轉(zhuǎn)化成網(wǎng)絡(luò)請求的洁奈?
(3) 網(wǎng)絡(luò)請求我們一般采用異步請求间唉,那么請求結(jié)果回來時,是如何進行線程切換的利术,即切換到主線程呈野?
Retrofit 實例構(gòu)建
構(gòu)建 Retrofit 實例是通過 Retrofit.Builder 來構(gòu)建的,采用構(gòu)建者模式印叁,配置參數(shù)更清晰被冒,而且能夠鏈式調(diào)用
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
接下來就來看下 Builder 中有哪些參數(shù)
public static final class Builder {
// 平臺類型對象:Android
private final Platform platform;
// 網(wǎng)絡(luò)請求的工廠,默認為 okhttp3 中的 OkHttpClient,OkHttpClient 實現(xiàn)了 okhttp3.Call.Factory
private @Nullable okhttp3.Call.Factory callFactory;
// 網(wǎng)絡(luò)請求的url地址,如 www.baidu.com
private HttpUrl baseUrl;
// 數(shù)據(jù)轉(zhuǎn)換器工廠的集合
private final List<Converter.Factory> converterFactories = new ArrayList<>();
// 網(wǎng)絡(luò)請求適配器工廠的集合
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
// 回調(diào)方法執(zhí)行器
private @Nullable Executor callbackExecutor;
// 是否校驗接口(針對 java8轮蜕,java8 中接口方法有默認實現(xiàn))
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
// 默認是 OkHttpClient
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
// 默認是 Android平臺 中的主線程調(diào)度器
callbackExecutor = platform.defaultCallbackExecutor();
}
// 網(wǎng)絡(luò)請求適配器工廠的集合
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// 數(shù)據(jù)轉(zhuǎn)換器工廠的集合
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
// 創(chuàng)建 Retrofit 實例
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
}
使用 Builder 構(gòu)建 Retrofit 可以設(shè)置這幾個參數(shù):
參數(shù) | 描述 | 說明 |
---|---|---|
Platform | 平臺類型 | 支持 Android昨悼,IOS,Java8 |
okhttp3.Call | 用來網(wǎng)絡(luò)請求 Call 對象跃洛,默認為 OkHttpClient | 最終生成的是 okhttp3 中的 RealCall 對象率触,Retrofit 中的 OkHttpCall 是對 okhttp3.Call 的一個包裝 |
HttpUrl | 網(wǎng)絡(luò)請求的url地址 | 設(shè)置的基地址,如 www.baidu.com汇竭,接口中注解的是 path |
Converter | 數(shù)據(jù)轉(zhuǎn)換器 | 用于轉(zhuǎn)化數(shù)據(jù)葱蝗,將 responseBody 轉(zhuǎn)化為對象穴张,同也可以對請求完成轉(zhuǎn)化 |
CallAdapter | 網(wǎng)絡(luò)請求適配器 | 可以對 okhttp3.Call 進行包裝適配,如適配使用 Rxjava 請求 |
Executor | 請求結(jié)果調(diào)度執(zhí)行器 | 對網(wǎng)絡(luò)請求結(jié)果進行請求两曼,默認是 Android 平臺的 MainThreadExecutor皂甘,用來切換到主線程,可進行 UI 更新操作 |
上面表格中是對各個參數(shù)的一個說明合愈,有些參數(shù)可以不用設(shè)置叮贩,會有默認參數(shù):
(1) HttpUrl 必須指定,這個不用多說
(2) okhttp3.Call.Factory 這個參數(shù)可以不用設(shè)置佛析,默認是 OkHttpClient,OkHttpClient 是 okhttp3 中的彪蓬,它實現(xiàn)了 okhttp3.Call.Factory 這個接口寸莫,當然一般情況下,我們在使用時會自己設(shè)置一個 OkHttpClient档冬,對它設(shè)置一些 log 打印膘茎,證書驗證,添加 header 等
(3) Converter 使用來進行數(shù)據(jù)轉(zhuǎn)化的酷誓,一般使用 GsonConverterFactory披坏,默認是 BuiltInConverters
(4) CallAdapter.Factory 是用來生產(chǎn) CallAdapter 對象的,CallAdapter 是對 okhttp3.Call 進行包裝盐数,包裝后主要用于控制線程的切換操作棒拂,默認由平臺提供 platform.defaultCallAdapterFactory(callbackExecutor)
(5) Executor 是請求結(jié)果調(diào)度執(zhí)行器,用來切換到主線程玫氢,可進行 UI 更新操作帚屉,對于 Android 平臺,默認提供的是 MainThreadExecutor漾峡,默認通過 platform.defaultCallbackExecutor() 獲取
Builder 中完成這些參數(shù)的設(shè)置攻旦,就可以創(chuàng)建 Retrofit 的實例了,對于 Retrofit 的參數(shù)也就是 Builder 中的參數(shù)生逸,這就是構(gòu)建者模式完成的任務(wù)牢屋。有些參數(shù)可能不是很好理解,后面在流程中會慢慢引入槽袄。
構(gòu)建 Call
動態(tài)代理
public interface MyService {
@GET("v1/user")
Call<User> getUsers();
假設(shè)有這樣一個 Service 接口烙无,想實現(xiàn)構(gòu)建 Call實例,通過反射能夠做到么掰伸?
(1) 反射是用于獲取已創(chuàng)建實例的方法或者屬性皱炉,并對其進行調(diào)用或者賦值;
(2) 反射能夠加載一個類狮鸭,通過 newInstance 方法創(chuàng)建實例合搅,但是接口不行
基于這兩條多搀,可以得出對于接口,使用反射不能構(gòu)建出 Call 實例。在 java 中還有另外一個工具灾部,動態(tài)代理康铭。這里對動態(tài)代理的機制做一個簡單的介紹。
動態(tài)代理主要通過 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法創(chuàng)建接口代理實例赌髓,loader 為類加載器从藤,interfaces 是需要生成代理對象的接口數(shù)組,handler 是用于自定義處理邏輯的對象锁蠕。
Class<User> service = MyService.class;
MyInvocationHandler handler = new MyInvocationHandler();
MyService proxy = Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, handler);
Call<User> call = proxy.getUsers();
public class MyInvocationHandler implements InvocationHandler {
public MyInvocationHandler() {
}
// proxy 是代理實例對象
// method 這個參數(shù)表示傳入接口中的所有 Method 對象
// args => 這個參數(shù)對應(yīng)當前 method 方法中的參數(shù)
@Override
public void invoke(Object proxy, Method method, Object[] args) {
...
}
}
這么看有些童鞋可能還是不是很理解動態(tài)代理夷野,那么看下面的代理類:
public class MyServiceProxy implements MyService {
private InvocationHandler handler;
public MyServiceProxy(InvocationHandler handler) {
}
@Override
@GET("v1/user")
public Call<User> getUsers(){
try {
Method method = com.xx.proxy.MyService.class.getMethod("getUsers");
this.handler.invoke(this, method, null);
} catch(Exception e) {
e.printStackTrace();
}
}
}
這樣看來,代理類是這樣的一個類荣倾,是不是就能理解了動態(tài)代理的機制了悯搔。動態(tài)代理就是創(chuàng)建這樣一個類,然后通過類加載器加載到內(nèi)存舌仍,然后再通過反射創(chuàng)建出代理實例妒貌,obj 就是 MyServiceProxy 的一個實例。
Class clazz = classLoader.loadClass("com.xx.proxy.MyServiceProxy");
Constructor constructor = clazz.getConstructor(InvocationHandler.class);
Object obj = constructor.newInstance(handler);
Retrofit 中的動態(tài)代理
好铸豁,現(xiàn)在回到 Retrofit 中灌曙,看看 Retrofit 是如何使用動態(tài)代理創(chuàng)建 Call 對象的。
在 Retrofit 實例構(gòu)建中节芥,我們能夠拿到 Retrofit 對象 retrofit在刺,通過這個對象調(diào)用 create 方法創(chuàng)建 MyServiceProxy 實例,即 retrofit.create(MyService.class)藏古。
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 方法是 Object 的一個方法增炭,則直接執(zhí)行
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 如果是 java8 中接口的默認實現(xiàn),則直接執(zhí)行
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 重點是這三行拧晕,也是網(wǎng)絡(luò)請求執(zhí)行的代碼
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
我們先不看 InvocationHandler 中的執(zhí)行邏輯隙姿,很簡單,就是利用 Proxy.newProxyInstance() 方法創(chuàng)建一個 MyServiceProxy 實例厂捞,有了 service 對象输玷,就可以調(diào)用接口中的方法,來得到 Call 實例:
service.getUsers() ---> handler.invoke()
最終 handler.invoke() 返回的結(jié)果就是 Call 實例靡馁。
小結(jié)
(1)到這里欲鹏,已經(jīng)有了 MyServiceProxy 接口實例,就可以調(diào)用接口中的方法臭墨,我們第一個問題就有了答案赔嚎,是如何完成接口中方法調(diào)用的,實際上是通過動態(tài)代理,幫助我們生成一個代理類尤误,代理類實現(xiàn)了我們定義的網(wǎng)絡(luò)請求接口侠畔,動態(tài)代理生成一個實例,通過這個實例來調(diào)用接口中的方法损晤。
(2)Retrofit 的 create 方法這里用到了软棺,代理模式(動態(tài)代理)和外觀模式,外觀模式是給出一個接口尤勋,外界通過這個接口來得到想要的結(jié)果喘落,不需要關(guān)心其內(nèi)部各個子系統(tǒng)實現(xiàn)的細節(jié),當然最冰,外觀模式不是必要的瘦棋。但是有了外觀模式,對于 Retrofit 的使用者使用起來更加方便和簡潔锌奴。
invoke 方法具體邏輯
//(1)創(chuàng)建 ServiceMethod
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//(2)創(chuàng)建 OkHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//(3)包裝或者適配 okHttpCall
serviceMethod.adapt(okHttpCall);
1 創(chuàng)建 ServiceMethod
對于我們定義的網(wǎng)絡(luò)接口中的每個方法兽狭,都對應(yīng)一個 ServiceMethod 對象,源碼中采用了緩存機制鹿蜀,以 method 為 key,ServiceMethod 對象為 value,緩存起來服球,這樣能夠提高效率茴恰,一個接口第二次調(diào)用時,不必重新創(chuàng)建 ServiceMethod 對象斩熊。
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
接著看 ServiceMethod 對象首次通過 Builder 模式創(chuàng)建過程往枣。
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 方法注解
this.methodAnnotations = method.getAnnotations();
// 方法參數(shù)類型數(shù)組
this.parameterTypes = method.getGenericParameterTypes();
// 方法參數(shù)注解數(shù)組(2維數(shù)組)
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
// (1) 創(chuàng)建 callAdapter
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
// (2) 創(chuàng)建 Converter
responseConverter = createResponseConverter();
// (3) 解析方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// 注意事項一
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
// (4) 生成每個參數(shù)注解的解析輔助類 ParameterHandler,一個 ParameterHandler 可能對應(yīng)一個或者多個注解
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
// 注意事項二
// 方法注解和參數(shù)注解解析后的錯誤項粉渠,這里便于我們更好的使用 Retrofit
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
(1) 創(chuàng)建 callAdapter分冈,實際上是通過 retrofit 實例,最終調(diào)用 nextCallAdapter() 霸株,查找在創(chuàng)建 Retrofit 對象時雕沉,callAdapterFactories 集合中的 CallAdapter,默認是 platform.defaultCallAdapterFactory() 得到的 new ExecutorCallbackCall<>(callbackExecutor, call)去件,負責(zé)將原本 call 回調(diào)轉(zhuǎn)發(fā)至UI線程坡椒。
(2) 創(chuàng)建 Converter,同樣類似尤溜,最終調(diào)用 nextResponseBodyConverter 方法倔叼,查找創(chuàng)建 Retrofit 對象時,converterFactories 集合中的 Converter.Factory宫莱,來拿到responseConverter對象丈攒,尋找的依據(jù)主要看該 converter 能否處理你編寫方法的返回值類型,默認為 BuiltInConverters,僅僅支持返回值的實際類型為 ResponseBody 和 Void巡验,也就說明了默認情況下际插,是不支持 Call < User > 這類類型的,所以一般我們使用 GsonResponseBodyConverter深碱。
(3) 方法注解解析腹鹉,通過 parseMethodAnnotation() 方法來完成,得到網(wǎng)絡(luò)請求的類型以及請求的參數(shù)敷硅,例如 @GET("v1/user")功咒,中相對路徑 v1/user,
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 HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
}
...
}
在解析方法注解后有一些注意事項绞蹦,這些是我們在使用 Retrofit 時可能出現(xiàn)的一些問題
// 注意事項一
// 沒有在方法上注解網(wǎng)絡(luò)請求類型
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
// 沒有請求體 body,說明不是 POST 請求力奋,那么不應(yīng)該出現(xiàn) @Multipart 注解和 @FormUrlEncoded 表單類型注解,
// 因為這兩個注解用于 POST 請求
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
(4) 生成每個參數(shù)注解的解析輔助類 ParameterHandler幽七,一個 ParameterHandler 可能對應(yīng)一個或者多個注解景殷,在生成 Request 時會使用到。方法參數(shù)注解有多個澡屡,在上一篇文章 Retrofit2.0 學(xué)習(xí)第二彈——使用篇 中有提到猿挚。
同樣,在參數(shù)注解解析后驶鹉,也有注意事項绩蜻,這些注意事項就是使用時的規(guī)則,規(guī)則是按照 http 請求的規(guī)則來的室埋。
// 注意事項二
// 方法注解和參數(shù)注解解析后的錯誤項办绝,這里便于我們更好的使用 Retrofit
// relativeUrl 是在 方法注解中獲取 @GET("v1/user"),
// 如果方法注解中沒有標注姚淆,那么在參數(shù)注解中應(yīng)該打上 @Url 注解孕蝉,指明地址的相對路徑
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
// 不是 POST 請求,去打上了 @Body 注解腌逢,會報錯
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
// 方法注解上有 @FormUrlEncoded 注解降淮,參數(shù)中需要有 @Field 注解或者 @FieldMap 注解
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
// 方法注解上有 @Multipart 注解,參數(shù)中需要有 @Part 注解或者 @PartMap 注解
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
經(jīng)過一系列的校驗之后上忍,沒有拋出錯誤骤肛,就可以創(chuàng)建一個 ServiceMethod 對象。
2 創(chuàng)建 OkHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
這一步?jīng)]什么說的窍蓝,就是創(chuàng)建 OkHttpCall 對象而已腋颠。
3 適配 okHttpCall
serviceMethod.adapt(okHttpCall) 調(diào)用 ServiceMethod 中的 adapt() 方法,還記得在創(chuàng)建 ServiceMethod 時獲取的 callAdapter 么吓笙,在平臺類型 Android 中提供的 ExecutorCallAdapterFactory.get() 方法生成的 CallAdapter 對象淑玫,再通過 CallAdapter 對象 adapt() 方法得到 ExecutorCallbackCall 對象,這樣 Call 請求對象的構(gòu)建過程就完成了。
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
...
}
}
ExecutorCallbackCall 是對 Executor 的一個裝飾絮蒿,采用的是裝飾者模式尊搬,在請求回調(diào)時通過 MainThreadExecutor 切換到 UI 線程,切換過程中先通過 Call 等待回調(diào)土涝, run 方法執(zhí)行時佛寿,也有判斷。
這個 Call 實際上是步驟 2 中創(chuàng)建的 OkHttpCall 對象但壮,在 ExecutorCallbackCall 中是一個靜態(tài)代理對象冀泻,通過 OkHttpCall 執(zhí)行同步請求方法 execute() 或者 異步方法 enqueue(final Callback< T > callback)。
小結(jié):這一部分主要在拿到 service 代理對象后蜡饵,調(diào)用接口方法獲取 Call 對象弹渔。過程中最重要就是 ServiceMethod,具體的工作都交給它來完成,ServiceMethod 對象進行網(wǎng)絡(luò)請求參數(shù)配置:通過解析網(wǎng)絡(luò)請求接口方法的參數(shù)溯祸、返回值和注解類型肢专,從 Retrofit 中獲取對應(yīng)的網(wǎng)絡(luò)請求的 url 地址、網(wǎng)絡(luò)請求執(zhí)行器焦辅、網(wǎng)絡(luò)請求適配器博杖、數(shù)據(jù)轉(zhuǎn)換器,最后通過調(diào)用 callAdapter.adapt 方法得到一個 Call 對象筷登,適配的目的就是對 Call 請求回調(diào)進行操作欧募,如果是異步請求,將異步線程切換到 UI 線程仆抵。
調(diào)用 Call 執(zhí)行請求
在上一步 Call 對象構(gòu)建過程中,最終得到的是一個 ExecutorCallbackCall 對象种冬,那么就看看 ExecutorCallbackCall 是如何執(zhí)行網(wǎng)絡(luò)請求的镣丑。
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
ExecutorCallbackCall 內(nèi)部有 execute 和 enqueue 方法,即同步和異步執(zhí)行方法娱两,在創(chuàng)建 ExecutorCallbackCall 對象過程中莺匠,我們知道 ExecutorCallbackCall 實際上是通過 OkHttpCall 這個代理來完成請求的,我們看下 OkHttpCall 的異步請求 enqueue 方法十兢。
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
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 {
// 創(chuàng)建 call 對象
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
// 異步請求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
首先是構(gòu)建 Call 對象趣竣,這個 Call 不是我們步驟 2 中的 Call 對象,而是 okhttp3.Call 對象旱物,真正完成網(wǎng)絡(luò)請求的對象遥缕,我們構(gòu)建的 Call 是對它的一個外層包裝,okhttp3.Call 的創(chuàng)建需要 一個 Request 參數(shù),這個應(yīng)該有 ServiceMethod 來完成宵呛,因為 ServiceMethod 對象中包含網(wǎng)絡(luò)請求的全部參數(shù)单匣,構(gòu)建最終調(diào)用 ServiceMethod 的 toCall 方法。
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return callFactory.newCall(requestBuilder.build());
}
ServiceMethod 對象中的參數(shù)就是在上面 retrofit.loadServiceMethod(method) 創(chuàng)建過程中賦值的,包括解析方法注解户秤,方法參數(shù)注解码秉,最終構(gòu)建出 Request 對象,callFactory 實際上是 OkHttpClient鸡号。
到這里就可以回答第二個問題【方法上的注解是如何被解析转砖,轉(zhuǎn)化成網(wǎng)絡(luò)請求的?】鲸伴,就是在 serviceMethod 創(chuàng)建過程中完成的府蔗,解析方法注解,方法參數(shù)注解解析等挑围,然后在 toCall 方法中進行拼接完成礁竞,當然不是簡單地拼接,具體過程這里就不再分析了杉辙。
有了 okhttp3.Call 對象模捂,接著就可以調(diào)用 call.enqueue() 方法執(zhí)行異步請求。請求的具體過程這里不展開蜘矢,具體過程是調(diào)用了 okhttp3.Call 執(zhí)行的狂男,后面會單獨寫一篇 okhttp3 的文章。請求結(jié)果如果順利品腹,如何解析岖食?
通過調(diào)用 OkHttpCall # response = parseResponse(rawResponse),無需看代碼應(yīng)該也能夠腦補出來舞吭, 如果你還記得在構(gòu)建 OkHttpCall 對象時泡垃,將 ServiceMethod 對象作為參數(shù)傳遞進去,所以 parseResponse 最后調(diào)用的是 ServiceMethod 中的 Conver 來進行數(shù)據(jù)解析工作的羡鸥。
最后還剩下一個問題蔑穴,回調(diào)后如何切換線程到 UI 線程?回頭看下 ExecutorCallbackCall 中的 enqueue 方法惧浴,callbackExecutor 實際是 MainThreadExecutor存和,callbackExecutor 的 execute方法最后是通過主線程的 Handler 切換到 UI 線程中
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
到這里,Retrofit 的請求過程基本就分析完了衷旅,其請求的主要過程:
(1) 請求過程實際由代理 OkHttpCall 發(fā)起捐腿,需要構(gòu)建 okhttp3.Call 對象
(2) 構(gòu)建 okhttp3.Call 對象需要參數(shù) Request,Request 對象構(gòu)建參數(shù)在 ServiceMethod 對象中在創(chuàng)建時就已經(jīng)準備好柿顶,serviceMethod.toCall() 方法就是利用這些參數(shù)完成 Request 構(gòu)建茄袖,生成 okhttp3.Call 對象。
(3) okhttp3.Call 請求結(jié)果回調(diào)時九串,對數(shù)據(jù)的解析最終還是通過 serviceMethod.toResponse() 來完成解析的绞佩。
(4) 異步請求是在子線程寺鸥,Retrofit 默認是通過 MainThreadExecutor 的來切換到 UI 線程。
總結(jié)
Retrofit 整個源碼分析也就差不多了品山,整體流程基本覆蓋到胆建,那么最后再總結(jié)一下:
1、首先構(gòu)造 Retrofit肘交,主要參數(shù)笆载,baseurl、callFactory(默認okhttpclient)涯呻、converterFactories凉驻、adapterFactories,excallbackExecutor
2、通過 create() 方法拿到接口的實現(xiàn)代理類复罐,這里利用動態(tài)代理來實現(xiàn)
3涝登、在 invoke 方法內(nèi)部,拿到方法注解以及方法參數(shù)效诅,方法參數(shù)注解等胀滚,構(gòu)造 ServiceMethod,ServiceMethod 完成注解解析乱投,構(gòu)建 Request 和 數(shù)據(jù)轉(zhuǎn)換等大量工作咽笼。最后 calladapter 對 Call 進行裝飾返回。
4戚炫、拿到 Call 就可以執(zhí)行 enqueue 或者 execute 方法了剑刑。
以上分析并不是基于 Retrofit 與 Rxjava 結(jié)合的分析,關(guān)于 Rxjava 部分的分析双肤,有興趣的童鞋可以自行分析下施掏,重點也是集中在對 Call 的包裝和線程切換部分。