標簽: Android
先看看這張圖
Retrofit
在學習Android的時候,我最熟悉的網(wǎng)絡請求框架莫過于OKHttp + Retrofit肋坚,反反復復用了很多次卓鹿,個人感覺Retrofit的兼容和解耦做的太好了重荠,這里想要試著分析一下Retrofit的源碼。
RESTful 原則
在我們使用Retrofit這個框架的時候挡篓,我們都需要后端的接口遵循RESTful原則婉陷,那什么是RESTful原則呢帚称?
RESTful是Representational State Transfer的縮寫,翻譯過來就是“表現(xiàn)層狀態(tài)轉(zhuǎn)化”秽澳,他是基于HTTP協(xié)議的闯睹。
- 表現(xiàn)層:我們訪問服務器是為了“增、刪担神、改楼吃、查”服務器上面的資源(數(shù)據(jù)),資源的對應的是一段文本(text)妄讯、一張圖片孩锡、一首歌曲或者一段音頻等,那么這里我們就說這些資源的實體就是表現(xiàn)層亥贸。
- 狀態(tài)轉(zhuǎn)化:當我們通過用“增浮创、刪、改砌函、查”的方式訪問服務器的時候,服務器的資源實體可能會發(fā)生變化溜族,對應的狀態(tài)也會相映的變化讹俊,這就是狀態(tài)轉(zhuǎn)化。
- 客戶端怎么進行“增煌抒、刪仍劈、改、查”寡壮? 通過HTTP協(xié)議贩疙,具體就是用HTTP提供的GET、POST况既、DELETE这溅、PUT的方式。
Retrofit分層
我們導入Retrofit的時候棒仍,發(fā)現(xiàn)我們導入的包分為了三個部分:包裝OKHttp的Retrofit部分悲靴,兼容RxJava的部分和兼容Gson的部分。
一莫其、包裝OKHttp
我們來看看這個部分的目錄:
- 首先這里有一個子目錄http癞尚,進去看我們就可以發(fā)現(xiàn)里面定義了若干的關于http協(xié)議的注解(包括GET、POST乱陡、PUT和DELETE等)浇揩。
- 接下來就是Retrofit以及它包裝的網(wǎng)絡請求執(zhí)行器,請求的構(gòu)建器憨颠,響應胳徽、轉(zhuǎn)化器、線程池和工具等等(以上沒按照順序)
二、兼容Gson
我們來看看這個部分的目錄:
這個部分很簡單膜廊,只包含了三個部分:Gson轉(zhuǎn)換器的工廠乏沸、Gson請求體的轉(zhuǎn)換器和Gson響應體的轉(zhuǎn)換器。
三爪瓜、兼容RxJava
我們再來看看這個部分的目錄:
這個部分我們可以看到很多繼承自RxJava的Observable對象蹬跃,都由RxJava2CallAdapter封裝,最后由它的工廠類RxJava2CallAdapterFactory創(chuàng)建出來铆铆。
Retrofit 流程源碼分析
一般情況下我們使用Retrofit的代碼如下:
mApiService = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.client(getClient())
.build()
.create(ApiService.class);
先是通過Retrofit的構(gòu)建器構(gòu)建一個Retrofit對象蝶缀,前面的幾個鏈式調(diào)用都是為了支持其他三方庫的功能,我們直接去看Retrofit的構(gòu)建器的build()方法薄货。
Retrofit.Builder.java
//成員
//當前的平臺
private final Platform platform;
//網(wǎng)絡請求執(zhí)行器的工廠
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
//可能會用到的轉(zhuǎn)換器工廠的集合
private final List<Converter.Factory> converterFactories = new ArrayList<>();
//可能會用到的適配器工廠的集合
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
//可能會用到的線程池翁都,默認為null
private @Nullable Executor callbackExecutor;
//是否在調(diào)用create()方法時,驗證傳入的接口中的所有方法
private boolean validateEagerly;
.......
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 制作適配器的防御副本并添加默認的呼叫適配器.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// 制作轉(zhuǎn)換器的防御副本.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
我們可以看見谅猾,這里和簡單的構(gòu)建者模式?jīng)]什么區(qū)別柄慰,初始化需要用到的成員變量,然后再直接通過Retrofit的構(gòu)造函數(shù)創(chuàng)建一個實例對象税娜,接下來我們?nèi)タ纯碿reate()方法坐搔。
public <T> T create(final Class<T> service) {
//驗證服務接口,服務接口必須是一個interface對象敬矩,且它沒有任何父接口
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//通過動態(tài)代理創(chuàng)建服務接口的實現(xiàn)類
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的方法概行,不做任何處理
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//這個條件判斷在Retrofit3.2.0時一直為false,其他版本不知道
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//這里通過服務接口的方法加載了一個ServiceMethod對象
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
在create()方法中,首先驗證了我們傳入的服務接口類弧岳,然后通過動態(tài)代理拿到方法和參數(shù)凳忙,通過拿到的方法加載ServiceMethod對象,那么ServiceMethod是干什么的呢禽炬?注釋是這么說的:將接口的方法調(diào)整為Http調(diào)用涧卵。我們先保留疑問,去看一下loadServiceMethod()方法做了什么:
ServiceMethod<?, ?> loadServiceMethod(Method method) {
//通過緩存拿到
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 沒有緩存就通過構(gòu)建器構(gòu)建一個新的ServiceMethod
result = new ServiceMethod.Builder<>(this, method).build();
//緩存
serviceMethodCache.put(method, result);
}
}
return result;
}
這個方法的干的事情就是腹尖,判斷是否有緩存艺演,有就直接返回,沒有就通過構(gòu)建器構(gòu)建一個新的ServiceMethod對象桐臊,這里的緩存是通過CurrentHashMap胎撤,鍵為方法,值為ServiceMethod對象断凶。這里模擬第一次調(diào)用伤提,沒有緩存,所以我們器看看ServiceMethod的構(gòu)建器:
Builder(Retrofit retrofit, Method method) {
//配置成員變量
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
//拿到適配器
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?");
}
//拿到轉(zhuǎn)換器
responseConverter = createResponseConverter();
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).");
}
}
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);
}
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);
}
- 這里先拿到適配器认烁,判斷適配器的響應類型是否合法
- 然后再拿到轉(zhuǎn)換器
- 循環(huán)解析——服務接口中被調(diào)用的方法上的注解
- 檢查各項數(shù)據(jù)肿男,new出ServiceMethod實例
下面我們依次分析這幾步:
第一步: 拿到適配器
private CallAdapter<T, R> createCallAdapter() {
//獲取通用的返回類型
Type returnType = method.getGenericReturnType();
//返回類型通配符或者變量類型
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
//返回類型不能是無返回類型
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
//拿到傳入該方法的的注解
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
這里先是判斷了服務接口中介汹,被用戶調(diào)用的方法的返回類型是否合法,合法之后拿到該方法的注解舶沛,轉(zhuǎn)入Retrofit中調(diào)用callAdapter()方法嘹承,下面我們?nèi)タ纯催@個方法:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
這里直接就調(diào)用了nextCallAdapter()方法,我們繼續(xù)跟進:
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
// 判斷參數(shù)是否為空
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
//找到與傳入?yún)?shù)值相等的變量在List中的索引
int start = adapterFactories.indexOf(skipPast) + 1;
//循環(huán)遍歷找到需要的適配器
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
......
}
這里進行了參數(shù)的非空判斷如庭,然后循環(huán)遍歷List叹卷,我們看向第十行這里調(diào)用了CallAdapter.Factory的實現(xiàn)類(應該是RxJava2CallAdapterFactory)的get()方法,這個方法會判斷調(diào)用的服務接口里面的方法的返回類型坪它,是否為Completable骤竹、Flowable、Maybe往毡,Single蒙揣、Obervable,之后會直接new出來需要的適配器(Adapter)开瞭。
我們在去看看第二步:拿到轉(zhuǎn)換器
private Converter<ResponseBody, T> createResponseConverter() {
//獲取方法的注解
Annotation[] annotations = method.getAnnotations();
try {
//轉(zhuǎn)到Retrofit中去拿到轉(zhuǎn)換器
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
我們跟到Retrofit中去看看responseBodyConverter()方法怎么拿到轉(zhuǎn)換器的懒震。
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations){
return nextResponseBodyConverter(null, type, annotations);
}
這里和拿到適配器的流程很像,也調(diào)用了一個nextxxx()方法嗤详。
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
//檢查參數(shù)是否為空
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
//獲取參數(shù)的值獲取在List對應的索引
int start = converterFactories.indexOf(skipPast) + 1;
//循環(huán)遍歷挎狸,找到轉(zhuǎn)換器
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;
}
}
......
}
這里可以看見,拿到轉(zhuǎn)換器的過程和拿到適配器的過程十分相似断楷,重點還是第12行的responseBodyConverter()。根據(jù)我們平時的用法崭别,這個方法直接new出來了一個GsonResponseBodyConverter(Gson響應體轉(zhuǎn)換器)冬筒。
我們?nèi)タ纯吹谌剑?解析注解
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.");
}
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
這里解析注解主要有分為兩類:
- 1 通過parseHttpMethodAndPath()方法解析出網(wǎng)絡請求的方法和URL相對路徑
- 2 通過parseHeaders()方法解析出——需要添加的請求頭
這里具體的解析方式我們就不深究了。
接下來我們看看第四步:檢查各項數(shù)據(jù)茅主,拿到ParameterHandler舞痰,new出ServiceMethod實例。這里就不挖這些代碼了诀姚。
我們回到Retrofit的create()方法:
public <T> T create(final Class<T> service) {
//驗證服務接口响牛,服務接口必須是一個interface對象,且它沒有任何父接口
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//通過動態(tài)代理創(chuàng)建服務接口的實現(xiàn)類
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的方法赫段,不做任何處理
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//這個條件判斷在Retrofit3.2.0時一直為false,其他版本不知道
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//這里通過服務接口的方法加載了一個ServiceMethod對象
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
ServiceMethod的loadServiceMethod()加載完了呀打,接下來就是直接new出OkHttpCall(網(wǎng)絡執(zhí)行器),并把OkHttpCall通過RxJava2CallAdapter的adapt()方法傳過去糯笙,接下里我們看看adapt()方法:
public Object adapt(Call<R> call) {
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);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
首先通過服務接口中的方法的返回類型中的泛型贬丛,判斷被觀察者的種類(一般情況下我們都是responseObservable),然后通過服務接口中的方法的返回類型判斷是Flowable给涕、Single豺憔、Maybe或者就是Observable额获。
到這里我們的Retrofit一套簡單流程就基本就分析完了,當然這里是淺分析恭应,當然還有頗多存疑抄邀。
mApiService = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.client(getClient())
.build()
.create(ApiService.class);
前面分析總結(jié):create()中使用了動態(tài)代理,在實際調(diào)用服務接口中的方法時昼榛,把方法和參數(shù)傳給了ServiceMethod境肾,ServiceMethod通過構(gòu)建者模式創(chuàng)建,在build()方法中通過Retrofit拿到了適配器和轉(zhuǎn)換器褒纲,并且對方法的注解和參數(shù)進行了解析准夷,可以說ServiceMethod做了很多事情,最后ServiceMethod通過調(diào)用它拿到的適配器莺掠,進過判斷衫嵌,返回網(wǎng)絡請求中的被觀察者。
有些童鞋可能會想彻秆,網(wǎng)絡請求到底是在什么時候執(zhí)行的呢楔绞?
通過我們拿到的被觀察者,訂閱我們自己寫的觀察者時,進行的網(wǎng)絡請求透硝。具體的五垮,RxJava的訂閱方法subscrib()最終會調(diào)用subscribeActual()這個方法,這個方法是個抽象方法蔫耽,在Retrofit的取得適配器中的adapt()方法(我們上面分析過這個方法)會new出新的被觀察者,這個新的觀察者會覆寫subscribeActual()這個方法留夜,通過傳入的網(wǎng)絡執(zhí)行器發(fā)起網(wǎng)絡請求匙铡。
本片文章謝謝童鞋們的觀看。
本人Andorid小白碍粥,水平有限鳖眼,如果有不對的地方,希望大家提點一下我嚼摩。