Retrofit源碼解析
簡介
從事移動端開發的人應該都知道Retrofit庫,作爲一個第三方網絡封裝庫,許多App都會用到它,他提供了註解方式的網絡接口定義,自定義請求響應參數轉換等等功能,大大提高了開發效率;今天我們嘗試着來看看它背後的邏輯好在哪裏
Retrofit基本使用
public interface NetApi {
@POST("test/login")
LiveData<Response> test(@Body Request request);
}
NetApi api = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(CustomGsonConverterFactory.create())
.addCallAdapterFactory(new LiveDataCallAdapterFactory())
.build().create(NetApi.class);
以上代碼就是retrofit的基本使用了
- 定義網絡接口
- 配置Retrofit參數
- 反射創建網絡接口類
這裏大致說一下代碼中的關鍵點:
其一:test方法的POST註解標明這是一個POST方法,Body註解標明request最終要封裝到http的請求體中去
其二:Retrofit.Builder需要add兩個工廠類,一個convert用於轉換http的請求響應參數,另一個CallAdapter調用適配器用於發起網絡接口的調用邏輯及相關的操作
注意:相信你也發現了addCallAdapterFactory可以添加不同的調用適配器,這裏是LiveData的,或者你曾經還用過RXjava的適配器,而且現在還有Kotlin的協程Coroutine適配器,無論哪種適配器,它都需要完成網絡調用的發起工作以及回調工作
源碼解讀
需求分析
試想,你是Retrofit的設計者,思考一下,它要完成哪些功能?
安全與快捷問題,首先我希望用戶能很方便使用庫進行開發;其次,網絡庫中轉處理App的諸多數據,不希望別人能直接訪問網絡中的數據,我希望用戶無法修改(至少有一定難度)網絡請求響應參數
對象轉換問題,app網絡請求可能會有不同的對象封裝類型,最終都需要轉換我這邊的統一請求參數對象格式,以及統一響應對象格式,這塊我定義好接口轉換,讓使用者自己去實現
除了以上問題之外,還有http請求分爲很多方法(get/post/query…),如何根據不同的方法進行參數封裝、調用等;
最後,還有其他一些基本的設計問題,面向對象設計的幾大原則,內聚、耦合、可擴展等等
解讀源碼之前,先解釋後面源碼可能會遇到的成員以及類說明:
Retrofit中:
okhttp3.Call.Factory callFactory; okhttp底層網絡調用引擎,網絡都是由它去發起調用的
List<Converter.Factory> converterFactories; 轉換器工廠類集合,需要用到的轉換器都會add到這個集合
List<CallAdapter.Factory> adapterFactories; 調用適配器工廠類集合,需要用到的適配器都會add到這個集合
類ServiceMethod<R, T> :每個網絡接口方法都會創建一個ServiceMethod,把請求和響應參數以及註解以及適配器、轉換器都會封裝到裏面去
OkHttpCall以及OkHttpClient是最終網絡處理中心
帶着以上的問題,我們就從上面Retrofit.Builder()源碼開始看看吧!
Retrofit.Builder
這是一個建造者模式的類,用於參數較多時,快速構建最終需要的Retrofit類:
==========Retrofit.java==========
public Builder() {
this(Platform.get());
}
Builder(Platform platform) {
this.platform = platform;
converterFactories.add(new BuiltInConverters());
}
=======Retrofit.java=========
=======Platform.java=========
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
單利模式找到平臺類,
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
Android設備這裏肯定不爲0,所以PLATFORM=Android
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
}
Android是Platform的子類
static class Android extends Platform {
返回主線程執行的Executor
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
返回一個可以在主線程回調執行的調用適配器工廠類,記住他也是個調用適配器工廠類
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
主線程的Looper,這個線程任務最終會在主線程執行
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
============Platform.java==============
Builder的默認構造方法獲取一個Android平臺類,它可以提供在主線程執行能力,返回後賦值給Builder的platform成員;在Builder(Platform platform)構造方法內,converterFactories成員是一個ArrayList集合,存儲Converter.Factory類,這個是定義的一個抽象類,提供了java bean對象在http中的轉換標準,而BuiltInConverters是提供的默認convert轉換器,比如StringConvert、BufferConvert等等,默認的轉換器一般用不到,所以看不懂BuiltInConverters裏面的東西也沒關係,這裏看看Converter.Factory定義的接口:
public interface Converter<F, T> {
javabean對象轉換的方法,要從F類型轉換爲T類型
T convert(F value) throws IOException;
內部工廠類,用於提供不同功能的Convert
abstract class Factory {
生產一個轉換之前是ResponseBody類型,轉換之後類型未知的Convert,用於響應時
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
return null;
}
生產一個轉換之後是RequestBody類型,轉換之前類型未知的Convert,用於請求時
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
同上
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
獲取index未知的參數類型Type
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
獲取Type類型的class
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
從上述代碼得知,java bean對象轉換器做哪些工作了吧,實現他的接口即可,然後添加到Builder的converterFactories集合去;這裏我們就看看我們自定義GsonConvert是不是這樣的?
GsonConvert
public final class CustomGsonConverterFactory extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new CustomGsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[]
methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new CustomGsonRequestBodyConverter<>(gson, adapter);
}
}
響應轉換器
final class CustomGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
CustomGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
String response = value.string();
HttpStatus httpStatus = gson.fromJson(response, HttpStatus.class);
if (httpStatus.getcode != HttpStatus.success) {
value.close();
throw new ApiException(httpStatus.getCode(), httpStatus.getMessage(),httpStatus.getOperatorName());
}
MediaType contentType = value.contentType();
Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
InputStream inputStream = new ByteArrayInputStream(response.getBytes());
Reader reader = new InputStreamReader(inputStream, charset);
JsonReader jsonReader = gson.newJsonReader(reader);
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
這裏我們確實是這麼做的,重寫請求響應方法,提供其轉換器;使用了Gson庫幫我們進行轉換java對象,爲了對網絡請求錯誤統一,我們在Response裏面對服務端返回的code做了判別處理,集中處理異常;回到Builder的.addConverterFactory(GsonConverterFactory.create())這裏,builder源碼:
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
把轉換器加入到了converterFactories集合中去
調用適配器CallAdapter
本篇文章前面說到了,調用適配器我們可以添加RXJava、LiveData和協程Coroutine等等不同的適配器,如果現在我們的Retrofit裏面的adapterFactories集合已經存放了多個適配器了,那麼我們在調用某一個具體網絡方法如本文開始的test方法,那他該使用哪一個適配器呢?這就需要從衆多適配器中去尋找,以接口返回值類型去匹配過濾,我們只需要定義好CallAdapter標準的返回值匹配能力即可,接口如下:
調用適配器T返回值類型 R是請求類型
public interface CallAdapter<R, T> {
返回響應參數類型
Type responseType();
適配器發起網絡調用
T adapt(Call<R> call);
abstract class Factory {
生成一個CallAdapter調用適配器,完成從R到T的轉換,並且要調用網絡
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
以下兩個方法就是CallAdapter提供的參數匹配工具方法,快速查找到index處的參數類型以及class
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
上訴相關解釋請看註釋,然後我們在實現liveData適配器,只需要處理我們支持的接口方法返回值類型即可:
這個適配器只處理LiveData返回類型的網絡接口方法
public class LiveDataCallAdapterFactory extends CallAdapter.Factory {
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//我只能處理返回值類型爲LiveData.class的
if(getRawType(returnType) != LiveData.class){
return null;
}
returnType泛型類型,獲取第0處泛型類型
Type type = getParameterUpperBound(0, (ParameterizedType) returnType);
Class rawType = getRawType(type);
如果0處類型不爲ApiResponse,就不處理,拋錯誤,也就是LiveData<ApiResponse>
if(rawType != ApiResponse.class){
throw new IllegalArgumentException("type must be a resource");
}
if(!(type instanceof ParameterizedType)){
throw new IllegalArgumentException("resource must be paramterized");
}
獲取0處的參數類型,最終返回回來的是type類型即可
type = getParameterUpperBound(0, (ParameterizedType) type);
return new LivedataCallAdapter<Object>(type);
}
}
真正的調用適配器,這是一個LiveData類型的
public class LivedataCallAdapter<T> implements CallAdapter<T, LiveData<ApiResponse<T>>> {
private Type responseType;
public LivedataCallAdapter(Type responseType) {
this.responseType = responseType;
}
@Override
public Type responseType() {
return responseType;
}
adapt發起網絡調用了,參數Call實質是一個OkhttpCall
@Override
public LiveData<ApiResponse<T>> adapt(final Call<T> call) {
return new LiveData<ApiResponse<T>>() {
private AtomicBoolean stat = new AtomicBoolean(false);
@Override
protected void onActive() {
if(stat.compareAndSet(false, true)){
請求入隊,執行網絡操作
call.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
將返回的數據發送到liveData中去,訂閱了這個liveData的都可以收到
postValue(ApiResponse.Companion.<T>create(response));
}
@Override
public void onFailure(Call<T> call, Throwable t) {
postValue(ApiResponse.Companion.<T>create(t));
}
});
}
}
};
}
}
至此,CallAdapter適配器看完了;我們要記住Retrofit中有兩個工廠類集合ArrayList,一個裝轉換java-bean對象的轉換器Convert,另一個裝發起網絡調用的適配器CallAdapter;但是我們還不清楚這兩個適配器是是如何組織起來使用?如何調用哪些方法,參數封裝如何封裝,最後又返回來是如何實現的?
帶着問題,我們繼續看Retrofit.Builder.build()
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
因爲我們沒有傳入callFactory,所以builder代替我們new一個OkHttpClient
if (callFactory == null) {
callFactory = new OkHttpClient();
}
callbackExecutor爲null的,所以從platform獲取默認的回調執行器,這個platform
前文講過,defaultCallbackExecutor主要是獲取一個能回到主線程執行的能力
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
這裏把build進來的CallAdapter添加到adapterFactories去
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
同時這裏也會添加一個默認的CallAdapter,這個默認的也能完成網絡操作工作;
所以如果你不添加調用適配器CallAdapter也是可以的
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
添加轉換器Convert
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
=============================================================================
上訴代碼會添加一個默認的調用適配器platform.defaultCallAdapterFactory(callbackExecutor),這個適配器可以自動把網絡放到子線程操作,同時網絡返回時,在返回到主線程,所以我們可以不添加其他的RXJava、LiveData等適配器,具體用法如下:
1. 定義這樣的網絡接口
@POST("xyyc/login/")
Call<LoginResponse> test(@Body LoginRequest request);
2. 調用
apiService.test(request)
.enqueue(new Callback<LoginResponse>() {
@Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
}
@Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
第二部回到Callback就已經在主線程執行了,是不是很方便!而且它也支持任務取消、終止等;雖然沒有RXJava那樣花裏胡哨的功能強大,但是它簡單快捷,代碼量少,邏輯簡單
=============================================================================
Retrofit
接着上面看到,Builder就已經把Retrofit創建給配置好了,然後就是Retrofit調用Create創建我們定義的接口類;下面代碼要仔細看了,是Retrofit的核心邏輯:
參數service是我們定義的接口類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 {
// If the method is a method from Object then defer to normal invocation.
調用method的類是否爲Object,顯然不是
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
method是否爲platform的默認方法 顯示也不是
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
邏輯周到這裏了,根據調用方法的method從緩存中去取出
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
創建一個OkHttpCall請求
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
用callAdapter.adapt發起執行,這裏是不是很熟悉,對了,你沒猜錯,這就是前文
講到的CallAdapter,他會執行adapt方法,在adapte方法發起網絡調用,將這個okHttpCall
入隊enqueue到網絡任務中去
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
這裏我們看到發起調用是serviceMethod裏面的callAdapter裏面的adapt發起調用的,但是callAdapter裝載到Retrofit集合裏面去,可能有好幾個,他怎麼知道調用哪個呢?不慌,我們看看serviceMethod是如何來的,看以下代碼:
這個就是快速緩存接口類的所有方法
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
遍歷接口類中所有的method
for (Method method : service.getDeclaredMethods()) {
默認都是false,所以都會執行loadServiceMethod
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
loadServiceMethod查找方法也會調用它,serviceMethodCache類型是ConcurrentHashMap,
key爲method,value爲ServiceMethod;爲了保證併發效率,採用了分段鎖
ServiceMethod<?, ?> loadServiceMethod(Method method) {
先去serviceMethodCache集合中找,看是否找得到
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
雙檢測機制,保證查找效率
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
創建一個ServiceMethod並添加到緩存中去
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
因爲後面的邏輯很多都和ServiceMethod有關,所以我們必須去ServiceMethod裏面看看,它是如何被創建的?
ServiceMethod
首先從new ServiceMethod.Builder<>(this, method).build()這裏開始:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
獲取這個method的所有註解
this.methodAnnotations = method.getAnnotations();
獲取method的參數類型Type
this.parameterTypes = method.getGenericParameterTypes();
獲取method參數的註解
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
構建一個serviceMethod
public ServiceMethod build() {
得到這個method的調用適配器,看到沒?這裏已經綁定好了,每個ServiceMethod從
一開始就綁定了調用適配器CallAdapter
callAdapter = createCallAdapter();
確定method返回類型
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?");
}
同上也一開始就綁定好轉換器
responseConverter = createResponseConverter();
依次遍歷每個註解
for (Annotation annotation : methodAnnotations) {
這裏主要是根據註解解析註解中的參數,比如@POST會有參數路徑,以及body參數
設置好相對訪問路徑,參數等
parseMethodAnnotation(annotation);
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
獲取每個參數的註解
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
註解轉換器,根據參數中不同的註解產生不同的處理句柄
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
}
上面的邏輯業務都在註釋裏面了,邏輯比較簡單,但是仔細一看,會發現三個問題
(1)method怎麼知道自己綁定哪個調用適配器CallAdapter ?
(2)同上,使用哪個轉換器Convert ?
(3)參數如何封裝進去,如POST方式的Body的請求是一個java對象,怎麼弄到http的body ?
綁定調用適配器
話不多說,看源碼:
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.");
}
獲取方法method的註解
Annotation[] annotations = method.getAnnotations();
try {
從Retrofit的CallAdapter集合中去找,注意參數類型和註解
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);
}
}
查看retrofit源碼
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
start爲0
int start = adapterFactories.indexOf(skipPast) + 1;
遍歷所有的CallAdapter
for (int i = start, count = adapterFactories.size(); i < count; i++) {
調用每個CallAdapter的get方法,get方法返回他的適配器,這個get方法
傳入了method的返回值類型和方法註解
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
}
再次回頭看看CallAdapter的get方法,這裏我們用自定義LiveData的
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
首先就判斷返回值類型是不是一個LiveData的class,如果不是就沒必要執行了
這個returnType就是我們定義網絡接口方法的返回值類型
if(getRawType(returnType) != LiveData.class){
return null;
}
查看returnType的0處返回值類型,理解爲泛型
Type type = getParameterUpperBound(0, (ParameterizedType) returnType);
Class rawType = getRawType(type);
泛型必須是APIResponse,後面類似
if(rawType != ApiResponse.class){
throw new IllegalArgumentException("type must be a resource");
}
if(!(type instanceof ParameterizedType)){
throw new IllegalArgumentException("resource must be paramterized");
}
type = getParameterUpperBound(0, (ParameterizedType) type);
就創建了LivedataCallAdapter調用適配器
return new LivedataCallAdapter<Object>(type);
}
至此,調用適配器找到了;
做一個method綁定CallAdapter小結:
1 確定自己method的返回值returnType和註解annotation
2 遍歷retrofit的所有CallAdapterFactory工廠類,並且依次工廠類的get方法
3 get方法中,會根據returnType是否支持,支持就返回創建調用適配器,不支持返回null
4 找到adapter就綁定到ServiceMethod中去
這裏有兩個個疑問如下:(1)Retrofit會爲每個Method方法緩存到Map (2)每個Method都會綁定自己的適配器和轉換器,並且大部分適配器和轉換器都是new新的出來,而不是每個Method共用;結合上面兩點,而網絡訪問接口類一般生命週期較長,這樣會導致app的內存消耗較大,Retrofit爲什麼不根據網絡接口來存儲method,當某一個網絡接口類死亡後,就銷燬它裏面提供的所有method,否則這個Retrofit的method緩存就會越來越大
當然他這個也可以解決,使用多個Retrofit,這樣把Retrofit生命週期完結後,他這部分的緩存都會被清理掉,不過這個有點不合適
綁定轉換器
綁定轉換器和上面綁定調用適配器原理差不多,感興趣可以自行去查看源碼,這裏就不繼續闡述了
參數封裝
參數封裝也是一大核心點,比如GET我們可能傳遞的是動態路徑,POST需要封裝到Body中去,這裏以Body封裝爲例,在ServiceMethod.Builder的build方法中有一句:parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations),就是爲參數類型爲parameterType,參數註解爲parameterAnnotations提供一個參數處理句柄:
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
因爲註解annotation裏面可能還有註解參數等
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
.......
return result;
}
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Url) {
} else if (annotation instanceof Path) {
} else if (annotation instanceof Query) {
} else if (annotation instanceof QueryName) {
} else if (annotation instanceof QueryMap) {
} else if (annotation instanceof Header) {
} else if (annotation instanceof HeaderMap) {
} else if (annotation instanceof Field) {
} else if (annotation instanceof FieldMap) {
} else if (annotation instanceof Part) {
} else if (annotation instanceof PartMap) {
} else if (annotation instanceof Body) {
if (isFormEncoded || isMultipart) {
throw parameterError(p,
"@Body parameters cannot be used with form or multi-part encoding.");
}
if (gotBody) {
throw parameterError(p, "Multiple @Body method annotations found.");
}
Converter<?, RequestBody> converter;
try {
哈哈,終於找到了,找到轉換器,這裏會從retrfoit的轉換工廠集合去找,也是根據type
去找,找到了也要new一個綁定
converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
} catch (RuntimeException e) {
// Wide exception range because factories are user code.
throw parameterError(e, p, "Unable to create @Body converter for %s", type);
}
gotBody = true;
return new ParameterHandler.Body<>(converter);
}
return null; // Not a Retrofit annotation.
}
至此,ServiceMethod就構建好了,請求轉換器/響應轉換器Convert,調用適配器;
再次回到Retrofit的create方法中去,裏面用到了動態代理調用方法,在動態代理的方法調用最後幾句
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
發起調用
從上面代碼可知,執行了serviceMethod.callAdapter適配器的adapt方法,這個adapt方法以我們自定義LiveData看看
@Override
public LiveData<ApiResponse<T>> adapt(final Call<T> call) {
return new LiveData<ApiResponse<T>>() {
private AtomicBoolean stat = new AtomicBoolean(false);
@Override
protected void onActive() {
if(stat.compareAndSet(false, true)){
重點看這裏,就是講Call入隊,這個Call是一個OkHttpCall
call.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
postValue(ApiResponse.Companion.<T>create(response));
}
@Override
public void onFailure(Call<T> call, Throwable t) {
postValue(ApiResponse.Companion.<T>create(t));
}
});
}
}
};
}
從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 {
createRawCall實質就是retrofit中OkHttpClien創建的RealCall
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
將請求入隊,並配置okhttp3.Callback()回調接口,這裏實質就是Okhttp的用法了
用過okhttp的都知道,這個就是okhttp的調用方式
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
網絡響應java bean對象換磚
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
}
private void callFailure(Throwable e) {
....
}
private void callSuccess(Response<T> response) {
.....
}
});
}
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
......
調用ServiceMethod的toResponse,進行對象轉換,實質就是ServiceMethod裏面的
responseConvert,前文已講過
T body = serviceMethod.toResponse(catchingBody);
......
}
小結:
上面代碼可以看出okhttp的調用邏輯,以及網絡請求響應response的對象轉換;但是還看不見請求參數是如何封裝的?首先上面call會調用createRawCall創建,這個函數裏面
private okhttp3.Call createRawCall() throws IOException {
封裝了請求參數,會使用到ServiceMethod之前綁定的RequestConvert
Request request = serviceMethod.toRequest(args);
callFactory是一個OkhttpClient,newCall是一個RealCall類型
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
最後就是把這個請求入隊,交給okHttp底層的任務去了,OKHttp模塊沒有做過深入的研究,大致就是有幾個任務隊列,每個網絡請求都會加到任務隊列裏面去,線程池的方式去這些任務隊列中去取任務執行
至此,Retrofit的源碼大致就分析完結!
總結
Retrofit主要的東西就是上面這些東西,轉換器Convert提供java對象在Http傳遞過程中的轉換能力,調用適配器CallAdapter提供了根據不能類型的網絡訪問方法不同的調用邏輯,而組織他們的關係都是ServiceMethod來實現的,根據每個網絡接口方法的返回值類型、註解、請求參數格式等,保存到ServiceMethod中去,然後ServiceMethod根據這些信息從Retrofit的兩個工廠類集合去搜尋屬於自己的轉換器Convert和調用適配器,然後封裝請求參數、發起網絡調用以及最後的網絡返回響應數據轉換等工作。
Retrofit的設計方式,在於把核心的工作都用統一的標準(接口)定義好,自己實現一些默認的能力,更多的則是由用戶自己去實現,使Retrofit開發更自由化,根據自己的使用場景;所以,我們做設計時,不是把重要的內容自己實現,而是爲重要內容定義標準,由使用者自己去實現