OkHttp的請求分爲同步請求和異步請求,下面我們先來分析同步請求的執行流程。
首先,看一下OkHttp執行同步請求的簡單示例:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://baidu.com")
.build();
Response response;
try {
response = client.newCall(request).execute();
Log.d(TAG, response.body() != null ? response.body().toString() : null);
} catch (IOException e) {
e.printStackTrace();
}
第一步,我們new了一個OkHttpClient,使用了默認的構造函數。
public OkHttpClient() {
this(new Builder());
}
這裏返回了一個new Builder(). 這個大家應該很熟悉,一個Builder模式的寫法。跟進源碼部分,可以看到它主要做了一些成員變量的初始化工作。比如Dispatcher,是請求分發器,連接池管理的connectionPool, 我們後面將重點分析, 以及一些timeout的設置等。
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
第二步,下面我們看Request的初始化過程
Request request = new Request.Builder()
.url("http://baidu.com")
.build();
跟進Builder()方法,主要做了兩件簡單的事,默認爲GET方式,初始化了Header,保存頭部信息,傳入的url String構造HttpUrl對象。
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
再看Build()方法,直接用之前的Builder對象,構造一個request。
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;
}
第三步,通過下面的方法,得到responseresponse = client.newCall(request).execute();
我們看看call的創建過程
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
Call是一個接口,RealCall是Call的具體實現。這邊直接使用RealCall類的靜態方法newRealCall創建了一個RealCall對象
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
代碼也比較簡單,創建了一個RealCall對象,賦值了一個listener。繼續看RealCall的構造方法
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
可以看出,RealCall持有了之前構造的client request對象,賦值了一個重定向攔截器,關於攔截器,後面也會具體分析。
最後,執行call.excute()方法,繼續看具體實現類RealCall
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
首先,判斷了excuted標誌位是否爲true,因爲同一個請求只能執行一次,如果已經執行了 就拋出異常,沒執行過,就把標誌位置爲true。
然後,捕捉call堆棧,並且執行了listener的callStart方法,看一下。
/**
* Invoked as soon as a call is enqueued or executed by a client. In case of thread or stream
* limits, this call may be executed well before processing the request is able to begin.
*
* <p>This will be invoked only once for a single {@link Call}. Retries of different routes
* or redirects will be handled within the boundaries of a single callStart and {@link
* #callEnd}/{@link #callFailed} pair.
*/
public void callStart(Call call) {
}
註釋上可以看出,每次執行call的enqueued或execute方法時,就會開啓這個listener。往下看核心代碼
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
首先,執行了dispatcher的exexuted方法,dispatcher是OkHttp的請求分發器,對於同步請求,executed也比較簡單,只是把call放入了running這個隊列 synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
其實Dispatcher的作用,就是維持call請求發給他的狀態,然後內部維護了一個線程池,用於執行網絡請求。call在執行的過程中,通過dispatcher這個分發器類,把任務推到執行隊列當中,進行操作,操作完成,再執行等待隊列的任務。Dispatcher是OkHttp的核心之一,後面會具體分析。
接下來我們繼續代碼,同步請求隊列的定義,下面代碼中 的第三個。上面兩個,一個是異步的就緒隊列,一個是異步的執行隊列。
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
執行完dispatcher.executed()方法後,會通過getResponseWithInterceptorChain()方法得到response。這個其實是一個攔截器鏈方法,後面也會具體分析。
最後我們看一下finally方法,他會在請求結束後執行finished方法
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
可以看出,把我們正在執行的同步請求傳入,從當前隊列移除同步請求。這邊主要第三個參數我們傳入的是false,這裏是走不到promoteCalls()的,但異步請求會走到這裏,到時再分析。然後,計算了目前還在運行的請求。最後兩行有一個判斷,如果runningCallsCount爲0且idleCallback不爲null時,運行了idleCallback。
最後,我們總結一下同步請求
1.創建一個OkHttpClient對象
2.構建一個request對象,通過OkHttpClient和Request對象,構建出Call對象
3.執行call的execute方法。