標籤:res pretty over queue word ice 調用 遞迴 隊列
通過上一節,我們已經瞭解了如何使用OkHttp發送非同步請求,下載網狀圖片資訊並顯示到ImageView控制項上,從這一節開始我們就來開始研究一下其內部的實現流程和原理。因為整個流程相對而言還是比較複雜,因此對於流程的分析我劃分成以下幾個章節去介紹
- 流程概述
- 攔截器的原理
- HttpEngine中sendRequest的流程分析
- HttpEngine中readResponse的流程分析
這一節我們先來看一下整個流程的概述,先上一張時序圖
以片來自http://www.jianshu.com/p/db197279f053
就從上一些OkHttp的使用開始分析:
上一節我們通過OkHttpClient.newCall(Request)的方法建立出一個Call對象,
Call是一個介面代碼如下:
package okhttp3;import java.io.IOException;public interface Call { Request request(); Response execute() throws IOException; void enqueue(Callback responseCallback); void cancel(); boolean isExecuted(); boolean isCanceled(); interface Factory { Call newCall(Request request); }}
因此OkHttpClient需要給我們返回一個Call介面的實作類別,點擊去看一下,代碼如下:
/** * Prepares the {@code request} to be executed at some point in the future. */ @Override public Call newCall(Request request) { return new RealCall(this, request); }
可以發現,其實返回的是RealCall對象。
接下來在Activity中調用Call.enqueue(Callback)方法,點進去之後代碼如下:
在enqueue一參的方法中又調用了2參數的方法,並將第二個參數forWebSocket置為了false.
而在2參數的enqueue方法中,我們發現最終調用了client.dispatcher.enqueue的方法,並且將Callback和forWebSocket兩個參數封裝到了一個叫做AsyncCall的對象當中.
這個dispatcher就是OkHttpClient中的一個全域變數,點進去查看如下:
synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } }
Dispatcher內部是過一個線程池來執行,超過最大請求數後則先加入準備請求的隊列中,對於這個線程池後續會單獨用一篇部落格來講解,此時我們主要來整理一下整個請求流程,因此不做過多解釋。 以上代碼會執行到if代碼塊,然後執行executorService().execute(call); 看到這對於線程池有瞭解的同學應該能立馬想到AsyncCall其實就是一個Runnable對象,我們點進AsyncCall代碼中可以看到它就是繼承了NamedRunnable,而NamedRunnable又實現了Runnable介面並且在run方法中主動調用了execute的方法,如下所示:
而這個抽象的execute方法在AsyncCall中已經被實現,如下所示:
由可以看到,當執行一個AsyncCall的execute方法時,會調用一個叫做getResponseWithInterceptorChain的方法,並返回Response對象,然後通過介面回調的方式將此Response返回給我們在Activity中所實現的Callback介面並重新整理UI。
那這個getResponseWithInterceptorChain內部又是如何工作的呢??其實這個方法中的源碼很簡單,如下所示:
建立了一個ApplicationInterceptorChain對象,然後調用其proceed方法進行,接下來看一下ApplicationInterceptorChain的proceed代碼如下
在proceed方法中,判斷如果index小於OkHttpClient中攔截器集合的個數,則會遞迴建立新的ApplicationInterceptorChain對象,並將這個新的ApplicationInterceptorChain對象那個傳遞給index下標的攔截器的intercept方法
注意:此處有一個亮點,如果我們想自己實現Intercept一定要在intercept方法中主動調用chain.proceed方法,這樣整個遞迴迴圈才能順利的執行下去,反過來說我們也可以在某一個攔截器中將網路請求進行攔截,做法就是只要在攔截器中不調用proceed方法即可
對於攔截器的作用以及原理我會在後續章節中單獨分析
但是在這個遞迴迴圈中,最終index都會處於一個>=client.interceptors.size的階段,因此最終會調用最後一行代碼getResponse(request, forWebSocket)方法。這個方法是真正的發送網路請求並擷取Response的方法,其內部代碼如下所示:
,在getResponse方法中建立了一個HttpEngine的對象,然後分別調用HttpEngine的sendRequest和readResponse方法,這兩個方法依次是發送網路請求和讀取網路請求結果,最後將Response對象返回到之前說的getResponseWithInterceptorChain方法,並回傳給Activity中的Callback
對於HttpEngine內部實現後續會單獨再做分析。
最後用兩個圖來做一個流程總結
OkHttp面試之--OkHttp的整個非同步請求流程