Android熱門框架解析,你確定不來看看嗎?
OkHttp框架源碼深度剖析【Android熱門框架分析第一彈】
Retrofit框架源碼深度剖析【Android熱門框架分析第二彈】
什么是Retrofit?
準確來說,Retrofit 是一個 RESTful?的 HTTP 網絡請求框架的封裝。
原因:網絡請求的工作本質上是 OkHttp 完成,而 Retrofit 僅負責 網絡請求接口的封裝,當前最新的Retrofit底層使用的是OkHttp3。
?
上圖說明了如下幾點:
1. App應用程序通過 Retrofit 請求網絡,實際上是使用 Retrofit 接口層封裝請求參數、Header、Url 等信息,之 后由 OkHttp 完成后續的請求操作。
2. 在服務端返回數據之后,OkHttp 將原始的結果交給 Retrofit,Retrofit根據用戶的需求對結果進行解析。?
所以,網絡請求的本質仍舊是OkHttp完成的,retrofit只是幫使用者來進行工作簡化的,比如配置網絡,處理數據等 工作,提高這一系列操作的復用性。這也就是網上流行的一個不太準確的總結:okhttp是瑞士軍刀,retrofit則是將這把瑞士軍刀包裝成了一個非常好用的指甲鉗(專治甲溝炎哈哈)。
為什么選擇Retrofit?
我曾經寫過一篇關于熱門網絡請求框架OkHttp的詳細解析,但為什么我還要對Retrofit繼續寫文章呢?這肯定是因為Retrofit有它獨特的優勢。雖然OkHttp非常好用,但它也存在一些局限性。OkHttp最初的設計就是為了實現網絡請求,而在實際應用中我們發現了一些缺點,這也促使了Retrofit的誕生。雖然Retrofit只是對OkHttp進行了封裝,但它帶來了很多顯著的優點。
-
超級解耦:
Retrofit實現了接口定義、接口參數和接口回調的徹底解耦。這種設計不僅讓代碼更清晰、更易于維護,也使得代碼的復用性大大提高。 -
靈活的HTTP客戶端配置:
在Retrofit中,你可以輕松配置不同的HTTP客戶端來實現網絡請求,如OkHttp、HttpClient等。這種靈活性使得開發者可以根據項目需求選擇最合適的HTTP客戶端。 -
同步與異步支持:
Retrofit同時支持同步和異步請求,提供了更豐富的使用場景。此外,它還與RxJava無縫集成,方便進行響應式編程。 -
多種數據格式支持:
通過配置不同的反序列化工具類,Retrofit可以解析多種數據格式,如JSON、XML等。這樣,開發者可以根據API的具體需求選擇最適合的數據格式。 -
高效的請求速度:
由于Retrofit底層使用OkHttp,再加上其優秀的封裝和優化,Retrofit在請求速度上表現優異。此外,它使用方便、靈活且簡潔,極大地提高了開發效率。
就筆者自身使用而言,使用Retrofit會比使用OkHttp舒服的多,開發效率也會提升,okhttp需要手動解析數據,而Retrofit通過內置的轉換器可以自動解析數據;同時,在網絡請求時,Retrofit會自動幫你進行線程切換;除此之外,還使用動態代理的方式自動生成網絡請求Api,當你在使用完OkHttp以后,再使用Retrofit,一定會讓你欲罷不能的!
Retrofit對OkHttp做了什么?
Retrofit并沒有改變網絡請求的本質,也無需改變,因為Okhttp已經足夠強大,Retrofit的封裝可以說是很強大,里 面涉及到一堆的設計模式,可以通過注解直接配置請求,可以使用不同的http客戶端,雖然默認是用http ,可以使用 不同Json Converter 來序列化數據,同時提供對RxJava的支持,使用Retrofit + OkHttp + RxJava 可以說是目前比較 潮的一套框架,但是需要有比較高的門檻。
OkHttp網絡請求:
我們先來看看OkHttp是怎么進行網絡請求的。
庫的引入
implementation 'com.squareup.retrofit2:retrofit:2.11.0'// 如果使用 Gson 進行 JSON 解析implementation 'com.squareup.retrofit2:converter-gson:2.11.0'
如果你沒有使用過OkHttp,可以看我之前的文章,在頂部有介紹;當然,你也直接看下面的OkHttp的簡單使用。
// 1.創建clientval client = OkHttpClient.Builder().cookieJar(CookieJar.NO_COOKIES).callTimeout(10000, TimeUnit.MILLISECONDS).build()// 2.創建requestval request = Request.Builder().url("http://10.34.12.156:68080/admin-api").addHeader("Content-Type", "application/json").get().build()// 3.構建call對象val call = client.newCall(request)// 4.1調用call對象的同步請求方法val response = call.execute() // response對象中保存的有返回的響應參數4.2調用call對象的異步請求方法call.enqueue(object : Callback {override fun onFailure(call: Call, e: IOException) {Log.d("a", "onFailure:") // 失敗回調}override fun onResponse(call: Call, response: Response) {Log.d("b", "onResponse:") // 成功回調}})
Step1:創建HttpClient對象,也就是構建一個網絡類型的實例,一般會將所有的網絡請求使用同一個單例對象。
Step2:構建Request,也就是構建一個具體的網絡請求對象,具體的請求url,請求頭,請求體等等。
Step3:構建請求Call,也就是將具體的網絡請求與執行請求的實體進行綁定,形成一個具體的正式的可執行實體。
Step4: 后面就進行網絡請求了,然后處理網絡請求的數據了。
是不是看著還挺容易的,一步步的,很好使用呢?
Okhttp給用戶留下的問題:
1)用戶網絡請求的接口配置繁瑣,尤其是需要配置請求body,請求頭,參數的時候;
2)數據解析過程需要用戶手動拿到responsbody進行解析,不能復用;
3)無法適配自動進行線程的切換。
那么這幾個問題誰來解決? 對,retrofit!
?Retrofit網絡請求
1、創建 Retrofit 實例并配置:val retrofit: Retrofit = Retrofit.Builder().baseUrl(baseUrl) // 指定根路徑.addConverterFactory(GsonConverterFactory.create()) // 指定解析數據時使用的轉換庫.build()2、創建服務接口實例:val service: AppService = retrofit.create(AppService::class.java) 這個AppService就是定義的接口3、發起網絡請求:val call: Call<ResponseBody> = service.getPostData(user, pwd) ResponseBody是數據Bean,getPostData是接口定義的方法call.enqueue(object : Callback<ResponseBody> {override fun onResponse(call: Call<ResponseBody>?, response: Response<ResponseBody>) {if (response.isSuccessful) {// 請求成功處理Log.d("HttpUtil", "成功")// 這里可以處理響應數據} else {// 請求失敗處理Log.e("HttpUtil", "請求失敗")}}override fun onFailure(call: Call<ResponseBody>?, t: Throwable) {// 網絡請求失敗處理t.printStackTrace()Log.e("HttpUtil", "網絡請求失敗")}})
- step1
構建一個網絡請求的載體對象,和okhttp構建OkhttpClient對象有一樣的意義,只不過 retrofit在build的時候有非常多的初始化內容,這些內容可以為后面網絡請求提供準備,如準備 現成轉換Executor, Gson convert,RxJavaCallAdapter。
- step2(精髓)
使用 retrofit.create()
方法創建定義的服務接口 AppService
的實例。為統一配置網絡請求完成動態代理的設置。
- step3?
建具體網絡請求對象Request(service),在這個階段要完成的任務:
1)將接口中的注解翻譯成對應的 參數;
2)確定網絡請求接口的返回值response類型以及對應的轉換器;
3)講Okhttp的Request封裝成為Retrofit的 OKhttpCall。
總結來說,就是根據請求service 的Interface來封裝Okhttp請求Request。
通過下圖,讓我們來總結一下,retrofit是如何來封裝okhttp請求的。(左圖的Request都是OkHttp哈,寫錯了)
??
?大體的網絡流程是一致的,畢竟都是通過okhttp進行網絡請求。主要的步驟都是:創建網絡請求實體client->構建真 正的網絡請求-> 將網絡請求方案與真正的網絡請求實體結合構成一個請求Call->執行網絡請求->處理返回數據->處理 Android 平臺的線程問題。
在上圖中,我們看到的對比最大的區別是什么?
- 1)okhttp創建的是OkhttpClient,然而retrofit創建的是 Retrofit實例
- 2)構建藍色的Requet的方案,retrofit是通過注解來進行的適配
- 3)配置Call的過程中,retrofit是利用Adapter適配的Okhttp 的Call
- 4)相對okhttp,retrofit會對responseBody進行 自動的Gson解析
- 5)相對okhttp,retrofit會自動的完成線程的切換。
那么retrofit是如何完成這幾點的封裝的呢?我們繼續往下走,擼源碼。
Retrofit追溯源碼
我們從Retrofit構建這里開始入手,我們通過build拿到我們的retrofit對象,我們看看build干了什么。
public Retrofit build() {// 1. 檢查 baseUrl 是否為 nullif (this.baseUrl == null) {throw new IllegalStateException("Base URL required.");} else {// 2. 檢查 callFactory 是否為 null,如果是,則使用默認的 OkHttpClientCall.Factory callFactory = this.callFactory;if (callFactory == null) {callFactory = new OkHttpClient();}// 3. 檢查 callbackExecutor 是否為 null,如果是,則使用默認的 Platform.callbackExecutorExecutor callbackExecutor = this.callbackExecutor;if (callbackExecutor == null) {callbackExecutor = Platform.callbackExecutor;}// 4. 獲取 BuiltInFactories 實例BuiltInFactories builtInFactories = Platform.builtInFactories;// 5. 創建 callAdapterFactories 列表并添加默認的 CallAdapter 工廠List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);List<? extends CallAdapter.Factory> defaultCallAdapterFactories = builtInFactories.createDefaultCallAdapterFactories(callbackExecutor);callAdapterFactories.addAll(defaultCallAdapterFactories);// 6. 創建 defaultConverterFactories 列表List<? extends Converter.Factory> defaultConverterFactories = builtInFactories.createDefaultConverterFactories();int defaultConverterFactoriesSize = defaultConverterFactories.size();// 7. 創建 converterFactories 列表并添加默認的 Converter 工廠List<Converter.Factory> converterFactories = new ArrayList<>(1 + this.converterFactories.size() + defaultConverterFactoriesSize);converterFactories.add(new BuiltInConverters());converterFactories.addAll(this.converterFactories);converterFactories.addAll(defaultConverterFactories);// 8. 創建并返回新的 Retrofit 實例return new Retrofit(callFactory, this.baseUrl, Collections.unmodifiableList(converterFactories), defaultConverterFactoriesSize, Collections.unmodifiableList(callAdapterFactories), defaultCallAdapterFactories.size(), callbackExecutor, this.validateEagerly);}
}
抓重點:
? ? ? ? // 2. 檢查 callFactory 是否為 null,如果是,則使用默認的 OkHttpClient
? ? ? ? Call.Factory callFactory = this.callFactory;
? ? ? ? if (callFactory == null) {
? ? ? ? ? ? callFactory = new OkHttpClient();
? ? ? ? }
Call.Factory
是 retrofit2.Call.Factory
接口的一個實例,它的主要目的是為每一個網絡請求創建一個新的 Call
對象。也就是說,這里其實就是去取Call對象。這里實例化了OkHttpClient對象,我們繼續往下看。
?
可以看到,這個類實現了Call.Factory這個接口,看到這里,有沒有很熟悉?是不是和OkHttp一樣的套路?(如果你沒看過我寫的一篇OkHttp的文章,你可以去看下)?
public interface Call extends Cloneable {/** Returns the original request that initiated this call. */Request request();Response execute() throws IOException;void enqueue(Callback responseCallback);void cancel();boolean isExecuted();boolean isCanceled();Timeout timeout();Call clone();interface Factory {Call newCall(Request request);}
}
還記得OkHttp通過newCall方法構建的對象嗎?有沒有恍然大悟?原來和OkHttp是一樣的,只是包裝了一下而已。這里的Call.Factory
負責創建 Call
對象,而 Call
對象代表了一個可以執行的 HTTP 請求。通過 Call.Factory
,Retrofit
可以靈活地創建這些 Call
對象,支持不同的 HTTP 客戶端實現。
總結:
OkHttpClient是 http 請求的載體包含socket等可以復用的對象,協議配置等等一切。 Request 創建的是一個具體的有url,header,等請求信息的一個網絡請求,表示這個具體的請求。
Call 通往請求的,去執行請求的整個過程的一個抽象。也是進行網絡請求的最終接口。
所以,此次調用,目的就是創建了一個OkHttpClient,換句話說,這里的調用就是生產 Okhttp網絡請求需要的請求Call的,以備后面進行真正的網絡請求。
接下來,我們看第三步
? ? ? ? // 3. 檢查 callbackExecutor 是否為 null,如果是,則使用默認的 Platform.callbackExecutor
? ? ? ? Executor callbackExecutor = this.callbackExecutor;
? ? ? ? if (callbackExecutor == null) {//這里默認為空,所以我們只要不設置,這里都會自動取獲取的
? ? ? ? ? ? callbackExecutor = Platform.callbackExecutor;
? ? ? ? }
?我們先看,Executor是個什么玩意。非常簡單,一個接口里面有一個抽象方法。?
public interface Executor {void execute(Runnable var1);
}
我們再去看Platform.callbackExecutor拿到了什么。
final class Platform {@Nullablestatic final Executor callbackExecutor;static final Reflection reflection;static final BuiltInFactories builtInFactories;private Platform() {}static {switch (System.getProperty("java.vm.name")) {case "Dalvik":callbackExecutor = new AndroidMainExecutor();if (VERSION.SDK_INT >= 24) {reflection = new Reflection.Android24();builtInFactories = new BuiltInFactories.Java8();} else {reflection = new Reflection();builtInFactories = new BuiltInFactories();}break;......}}
}
可以看到,在android開發中,我們的?Platform.callbackExecutor會默認的拿到一個AndroidMainExecutor對象。我們再繼續深入。
final class AndroidMainExecutor implements Executor {private final Handler handler = new Handler(Looper.getMainLooper());AndroidMainExecutor() {}public void execute(Runnable r) {this.handler.post(r);}
}
可以看到,其實就是傳入了一個AndroidMainExecutor對象,并且它持有主線程的looper,看到這里,你有沒有想到為什么Retrofit可以自動完成線程切換呢?原因就在這里。其實,只要是android中的通信,基本都離不開handler的。 雖然這里已經把答案揭曉了,但是可能大家還是不理解,它是怎么實現線程切換的。
我們繼續看,它到底是怎么完成線程切換的。
callbackExecutor = new AndroidMainExecutor(); if (VERSION.SDK_INT >= 24) {reflection = new Reflection.Android24();builtInFactories = new BuiltInFactories.Java8();還記得這行代碼嗎? } else {reflection = new Reflection();builtInFactories = new BuiltInFactories();還記得這行代碼嗎? }
?我們通過new BuiltInFactories()獲得了這個BuiltInFactories這個對象。
class BuiltInFactories {BuiltInFactories() {}List<? extends CallAdapter.Factory> createDefaultCallAdapterFactories(@Nullable Executor callbackExecutor) {return Collections.singletonList(new DefaultCallAdapterFactory(callbackExecutor));}List<? extends Converter.Factory> createDefaultConverterFactories() {return Collections.emptyList();}@TargetApi(24)static final class Java8 extends BuiltInFactories {Java8() {}List<? extends CallAdapter.Factory> createDefaultCallAdapterFactories(@Nullable Executor callbackExecutor) {return Arrays.asList(new CompletableFutureCallAdapterFactory(), new DefaultCallAdapterFactory(callbackExecutor));}List<? extends Converter.Factory> createDefaultConverterFactories() {return Collections.singletonList(new OptionalConverterFactory());}}
}
BuiltInFactories builtInFactories = Platform.builtInFactories;在這里我們拿到了我們的builtInFactories的實例對象。
在第5步是,我們構建工廠的時候,用到了builtInFactories
// 5. 創建 callAdapterFactories 列表并添加默認的 CallAdapter 工廠List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);List<? extends CallAdapter.Factory> defaultCallAdapterFactories = builtInFactories.createDefaultCallAdapterFactories(callbackExecutor);callAdapterFactories.addAll(defaultCallAdapterFactories);
?調用builtInFactories.createDefaultCallAdapterFactories(callbackExecutor),這里傳入了我們在第3步拿到的callbackExecutor,繼續看createDefaultCallAdapterFactories這個方法做了什么。
List<? extends CallAdapter.Factory> createDefaultCallAdapterFactories(@Nullable Executor callbackExecutor) {return Collections.singletonList(new DefaultCallAdapterFactory(callbackExecutor));}
這里return Collections.singletonList(new DefaultCallAdapterFactory(callbackExecutor));我們繼續看?DefaultCallAdapterFactory。
DefaultCallAdapterFactory有個靜態內部類。這里通過構造方法,傳入我們的Executor對象和我們的Call。當我們調用enqueue方法時,其實就是調用我們call對象的exqueue方法,在exqueue方法中又將我們的onResponse和onFailure通過Executor的execute包起來,從而實現Retrofit的自動切換線程的功能。(看到這,可能你有點懵,你現在要知道一個點,它其實就是通過Executor將請求結果的響應包裝起來,發送給主線程。現在你可能無法將知識串起來,先記住,繼續往下看)
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;}public void enqueue(final Callback<T> callback) {Objects.requireNonNull(callback, "callback == null");this.delegate.enqueue(new Callback<T>() {public void onResponse(Call<T> call, Response<T> response) {ExecutorCallbackCall.this.callbackExecutor.execute(() -> {if (ExecutorCallbackCall.this.delegate.isCanceled()) {callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));} else {callback.onResponse(ExecutorCallbackCall.this, response);}});}public void onFailure(Call<T> call, Throwable t) {ExecutorCallbackCall.this.callbackExecutor.execute(() -> {callback.onFailure(ExecutorCallbackCall.this, t);});}});}.......}
? 然后其他的話,我們還看到很多factory,這些factory的話基本上是給我們解析數據等其他作用的,這里暫不深入。
現在,我們已經構建好了Retrofit,這些步驟用于進行后面請求的需要的內容的一個準備工作。也就是封裝Okhttp需要的準備工作。
?我們繼續往下看,下面兩行代碼需要連起來才能正確的被閱讀,因為,在create里面是使用了動態代理的技術方案,而動態代理是運行時生效的。AppService就是一個接口(相當于Api)里面有很多抽象方法就相當于不同的請求。
? ? ? ? 2、創建服務接口實例:val service: AppService = retrofit.create(AppService::class.java)?這個AppService就是定義的接口3、發起網絡請求:val call: Call<ResponseBody> = service.getPostData(user, pwd)?ResponseBody是數據Bean,getPostData是接口定義的方法
這里我們繼續看create的代碼。?
public <T> T create(final Class<T> service) {// 驗證服務接口是否合法this.validateServiceInterface(service);// 創建代理實例return Proxy.newProxyInstance(service.getClassLoader(), // 獲取服務接口的類加載器new Class[]{service}, // 代理的接口列表,這里只有一個接口new InvocationHandler() { // 代理調用處理器private final Object[] emptyArgs = new Object[0]; // 空參數數組,用于沒有參數的方法@Nullablepublic Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {// 如果是Object類的方法,直接調用if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);} else {// 如果參數為空,則使用空參數數組args = args != null ? args : this.emptyArgs;// 獲取平臺特定的反射實例Reflection reflection = Platform.reflection;// 如果是默認方法,通過反射調用默認方法return reflection.isDefaultMethod(method)? reflection.invokeDefaultMethod(method, service, proxy, args)// 否則,通過Retrofit加載服務方法,并調用它: Retrofit.this.loadServiceMethod(service, method).invoke(proxy, args);}}});
}
這里我們先將一下什么是動態代理。
在動態代理中,代理對象不需要實現接口,但是目標對象還是需要實現接口。代理對象的生成,是利用 JDK 的 API ,動態的在內存中構建代理對象。
在 Java 中,java.lang.reflect.Proxy
?類為對象生成代理提供了方法:
Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler())
- 參數一 service.getClassLoader():返回的是
service
接口的類加載器,用于加載這個接口及其方法。 - 參數二 new Class[]{service}:指定這個代理類能夠代理目標對象的哪些方法和接口;它包含了所有需要被代理的方法的聲明
- 參數三
InvocationHandler
:用來指定生成的代理對象在方法被調用時如何進行處理;
所以,service
參數本身并不包含實際的方法實現,它只是一個接口的類對象,定義了方法的簽名(方法名、參數類型、返回類型等)。當你調用這些方法時,實際上會進入 InvocationHandler
的 invoke
方法中,通過反射等機制來實現對這些方法的具體處理,從而實現代理模式。
因此,service
在這里不包含具體方法的實現,而是作為動態代理的基礎接口,通過動態代理技術來生成實際的代理對象,以便在運行時動態處理方法調用。
說完動態代理,我們繼續看代碼。
// 驗證服務接口是否合法this.validateServiceInterface(service);
?我將validateServiceInterface方法分為兩部分。
private void validateServiceInterface(Class<?> service) {第一部分if (!service.isInterface()) {throw new IllegalArgumentException("API declarations must be interfaces.");} else {Deque<Class<?>> check = new ArrayDeque(1);check.add(service);while(!check.isEmpty()) {Class<?> candidate = (Class)check.removeFirst();if (candidate.getTypeParameters().length != 0) {StringBuilder message = (new StringBuilder("Type parameters are unsupported on ")).append(candidate.getName());if (candidate != service) {message.append(" which is an interface of ").append(service.getName());}throw new IllegalArgumentException(message.toString());}Collections.addAll(check, candidate.getInterfaces());}第二部分if (this.validateEagerly) {Reflection reflection = Platform.reflection;Method[] var9 = service.getDeclaredMethods();int var5 = var9.length;for(int var6 = 0; var6 < var5; ++var6) {Method method = var9[var6];if (!reflection.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers()) && !method.isSynthetic()) {this.loadServiceMethod(service, method);}}}}}
?第一部分,主要做的是檢查我們的service是否是接口。如果不是接口,我們將繼續檢查它是否是泛型接口,如果定義了則拋出異常。這是因為,Retrofit 在創建服務接口代理對象之前檢查是否是泛型接口,是為了確保動態代理能夠正確地工作。只有非泛型的接口才能確保在運行時通過動態代理生成有效的代理對象,并且能夠正確地調用接口方法,實現網絡請求和響應的處理。
我們再看第二部分,第二部分其實是去進行實際的方法加載和驗證,對我們寫好的網絡請求進行驗證。這里默認為false,從而實現Retrofit在創建服務接口實例時不會急切地驗證接口方法。相反,它僅在實際調用方法時進行驗證。
這里我們分析一下它是如何驗證的。這里將我們獲得到的所有的方法進行遍歷,然后調用下面這個方法進行驗證。
this.loadServiceMethod(service, method);
?我們繼續看loadServiceMethod方法。
// 加載服務方法,并將其緩存起來// 參數:// service: 要加載方法的服務接口類// method: 要加載的方法ServiceMethod<?> loadServiceMethod(Class<?> service, Method method) {while(true) {// 從緩存中查找對應方法的 ServiceMethod 對象Object lookup = this.serviceMethodCache.get(method);if (lookup instanceof ServiceMethod) {// 如果緩存中已經有了該方法的 ServiceMethod 對象,則直接返回return (ServiceMethod) lookup;}if (lookup == null) {// 如果緩存中沒有該方法的 ServiceMethod 對象,則加鎖嘗試創建Object lock = new Object();synchronized (lock) {// 雙重檢查,確保只有一個線程創建 ServiceMethod 對象lookup = this.serviceMethodCache.putIfAbsent(method, lock);if (lookup == null) {// 創建 ServiceMethod 對象并放入緩存ServiceMethod result;try {result = ServiceMethod.parseAnnotations(this, service, method);} catch (Throwable var10) {// 如果創建過程中出現異常,則移除緩存并拋出異常this.serviceMethodCache.remove(method);throw var10;}this.serviceMethodCache.put(method, result);return result;}}}// 如果有其他線程正在創建 ServiceMethod 對象,則等待該線程完成并獲取結果synchronized (lookup) {Object result = this.serviceMethodCache.get(method);if (result != null) {return (ServiceMethod) result;}}}}
這里注釋里面寫的很清楚了。用緩存提高效率,沒有緩存則加鎖創建,這里使用的是雙重檢查。不過目前,我們還是沒有看見它是怎么驗證我們的方法的正確性的,所以我們需要繼續往下看。
result = ServiceMethod.parseAnnotations(this, service, method);
這里就是我們驗證的關鍵,調用parseAnnotations
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Class<?> service, Method method) {RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, service, method);Type returnType = method.getGenericReturnType();if (Utils.hasUnresolvableType(returnType)) {throw Utils.methodError(method, "Method return type must not include a type variable or wildcard: %s", new Object[]{returnType});} else if (returnType == Void.TYPE) {throw Utils.methodError(method, "Service methods cannot return void.", new Object[0]);} else {return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);}}
我們從parseAnnotations一路分析下去,我們將會看到以下代碼:
private void parseMethodAnnotation(Annotation annotation) {if (annotation instanceof DELETE) {this.parseHttpMethodAndPath("DELETE", ((DELETE)annotation).value(), false);} else if (annotation instanceof GET) {this.parseHttpMethodAndPath("GET", ((GET)annotation).value(), false);} else if (annotation instanceof HEAD) {this.parseHttpMethodAndPath("HEAD", ((HEAD)annotation).value(), false);} else if (annotation instanceof PATCH) {this.parseHttpMethodAndPath("PATCH", ((PATCH)annotation).value(), true);} else if (annotation instanceof POST) {this.parseHttpMethodAndPath("POST", ((POST)annotation).value(), true);} else if (annotation instanceof PUT) {this.parseHttpMethodAndPath("PUT", ((PUT)annotation).value(), true);} else if (annotation instanceof OPTIONS) {this.parseHttpMethodAndPath("OPTIONS", ((OPTIONS)annotation).value(), false);} else if (annotation instanceof HTTP) {HTTP http = (HTTP)annotation;this.parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());} else if (annotation instanceof retrofit2.http.Headers) {retrofit2.http.Headers headers = (retrofit2.http.Headers)annotation;String[] headersToParse = headers.value();if (headersToParse.length == 0) {throw Utils.methodError(this.method, "@Headers annotation is empty.", new Object[0]);}this.headers = this.parseHeaders(headersToParse, headers.allowUnsafeNonAsciiValues());} else if (annotation instanceof Multipart) {if (this.isFormEncoded) {throw Utils.methodError(this.method, "Only one encoding annotation is allowed.", new Object[0]);}this.isMultipart = true;} else if (annotation instanceof FormUrlEncoded) {if (this.isMultipart) {throw Utils.methodError(this.method, "Only one encoding annotation is allowed.", new Object[0]);}this.isFormEncoded = true;}}
這里對我們寫好的方法進行驗證。?那么方法正確難道方法就一定可行嗎?所以,Retrofit還對我們的請求結果進行驗證了。
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
通過這行代碼實現,代碼里面注釋寫的很詳細。
// 解析方法的注解和參數,生成對應的 HttpServiceMethod 對象// 參數:// retrofit: Retrofit 實例,用于創建適配器和轉換器// method: 當前要解析的方法// requestFactory: 請求工廠,包含請求方法和參數信息static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {// 是否為 Kotlin 的掛起函數boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;// 是否掛起函數需要返回響應對象boolean continuationWantsResponse = false;// 掛起函數返回體是否可為 nullboolean continuationBodyNullable = false;// 掛起函數返回類型是否為 Unitboolean continuationIsUnit = false;// 獲取方法的所有注解Annotation[] annotations = method.getAnnotations();Object adapterType;Type responseType;// 如果是 Kotlin 掛起函數if (isKotlinSuspendFunction) {Type[] parameterTypes = method.getGenericParameterTypes();// 獲取返回類型的實際泛型參數responseType = Utils.getParameterLowerBound(0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);// 如果返回類型是 Response 類型且包含泛型參數if (Utils.getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);continuationWantsResponse = true;} else {// 如果返回類型是 retrofit2.Call 類型,則拋出異常if (Utils.getRawType(responseType) == retrofit2.Call.class) {throw Utils.methodError(method, "Suspend functions should not return Call, as they already execute asynchronously.\nChange its return type to %s", new Object[]{Utils.getParameterUpperBound(0, (ParameterizedType) responseType)});}// 判斷返回類型是否為 UnitcontinuationIsUnit = Utils.isUnit(responseType);}// 創建一個參數化類型的 Call 類型adapterType = new Utils.ParameterizedTypeImpl((Type) null, retrofit2.Call.class, new Type[]{responseType});// 確保 SkipCallbackExecutorImpl 存在annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);} else {// 非 Kotlin 掛起函數,獲取方法的返回類型adapterType = method.getGenericReturnType();}// 創建調用適配器CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, (Type) adapterType, annotations);// 獲取適配器的響應類型responseType = callAdapter.responseType();// 校驗返回類型是否合法if (responseType == okhttp3.Response.class) {throw Utils.methodError(method, "'" + Utils.getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?", new Object[0]);} else if (responseType == Response.class) {throw Utils.methodError(method, "Response must include generic type (e.g., Response<String>)", new Object[0]);} else if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType) && !Utils.isUnit(responseType)) {throw Utils.methodError(method, "HEAD method must use Void or Unit as response type.", new Object[0]);} else {// 創建響應體轉換器Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);// 獲取 Retrofit 的調用工廠Call.Factory callFactory = retrofit.callFactory;// 如果不是 Kotlin 掛起函數,返回 CallAdapted 對象if (!isKotlinSuspendFunction) {return new CallAdapted(requestFactory, callFactory, responseConverter, callAdapter);} else {// 如果是 Kotlin 掛起函數,根據需要返回 Response 或 Body 的掛起函數對象return (HttpServiceMethod<ResponseT, ReturnT>) (continuationWantsResponse ?new SuspendForResponse<>(requestFactory, callFactory, responseConverter, callAdapter) :new SuspendForBody<>(requestFactory, callFactory, responseConverter, callAdapter, continuationBodyNullable, continuationIsUnit));}}}
好的,我們所有的準備工作以及相關的原理解析,我們都已經說明白了。那么當我們調用方法的時候,是怎么實現這一切的呢?是怎么串起來的呢?
3、發起網絡請求:val call: Call<ResponseBody> = service.getPostData(user, pwd) ResponseBody是數據Bean,getPostData是接口定義的方法call.enqueue(object : Callback<ResponseBody> {override fun onResponse(call: Call<ResponseBody>?, response: Response<ResponseBody>) {if (response.isSuccessful) {// 請求成功處理Log.d("HttpUtil", "成功")// 這里可以處理響應數據} else {// 請求失敗處理Log.e("HttpUtil", "請求失敗")}}override fun onFailure(call: Call<ResponseBody>?, t: Throwable) {// 網絡請求失敗處理t.printStackTrace()Log.e("HttpUtil", "網絡請求失敗")}})
這里我們調用getPostData方法進行網絡請求,結合retrofit的動態代理,我們將會執行下面的invoke方法。
public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);} else {args = args != null ? args : this.emptyArgs;Reflection reflection = Platform.reflection;return reflection.isDefaultMethod(method) ? reflection.invokeDefaultMethod(method, service, proxy, args) : Retrofit.this.loadServiceMethod(service, method).invoke(proxy, args);}}
注意看,Retrofit.this.loadServiceMethod(service, method).invoke(proxy, args);
當我們通過loadServiceMethod拿到我們的方法的時候,又調用了invoke函數。這里其實就是發起網絡請求以后,通過invoke結合適配器的adapt方法將我們的數據直接轉為我們的Bean。(或者結合RxJava使用)
我們看看HttpServiceMethod.adapt()方法:(其實是ServiceMethod的只不過HttpServiceMethod實現了ServiceMethod)。這里其實就是適配器的工作,你需要什么類型的數據就通過適配器適配,返回適配后的對象就是了。
final ReturnT invoke(Object instance, Object[] args) {retrofit2.Call<ResponseT> call = new OkHttpCall(this.requestFactory, instance, args, this.callFactory, this.responseConverter);return this.adapt(call, args);}
?總結
一般的Retrofit網絡請求的操作是指 Call.excute() & Call.enqueue()的過程,這個過程才是真正的網絡請求,因為,網絡配置、請求地址配置、Call適配、網絡請求requestBody、返回值responseBody轉化適配準備工作都已經完成。
在進行網絡請求的執行的時候,基本上就是調用,ServiceMethod中設置的各個內容
?1)OkHttpCall進行網絡請求,實則是進行okhttp的網絡請求;
2)利用 converter進行網絡請求數據的轉換,一般是Gson();
3)利用 rxjava observable構建 rxjava類型的責任鏈訪問方案,并進行線程切換;
4) 如果沒有rxjava的添加,那么就使用默認的callAdapter里面的callbackExecutor進行線程的切換 , 進行網絡請求.
?
學生記錄所做,如有錯誤,歡迎指出。?