1.OkHttp的簡單使用
一般情況下,對于網(wǎng)絡框架有兩種常見的使用場景,同步請求和異步請求肖抱。
同步請求:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("http://www.baidu.com").build();
Call call = client.newCall(request);
Response response = call.execute();
異步請求:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("http://www.baidu.com").build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
上面代碼比較簡單奋刽,并不是本文的重點瓦侮。旨在拋磚引玉...
2.OkHttp內部相關類的介紹
- OkHttpClient:Okhttp的主類,一般情況下設計成單列使用佣谐。
- Request:OkHttp的請求類肚吏,可以分裝了請求消息頭,消息實體相關的信息
- Response:OkHttp的響應類狭魂,分裝了相應碼罚攀,相應實體相關的信息
- Call:對于OkHttp來說,一個call對應一次網(wǎng)絡請求操作
- RealCall:Call接口的真正實現(xiàn)
- AsyncCall:當執(zhí)行的時移步請求時雌澄,會轉化成AsyncCall斋泄,它實現(xiàn)Runnable接口,是對RealCall的再次封裝
- Dispatcher:用來分發(fā)請求任務的類
- RetryAndFollowUpInterceptor:負責重連和重定向的攔截器
- BridgeInterceptor:橋攔截器镐牺,處理請求頭
- CacheInterceptor:緩存攔截器
- ConnectInterceptor:連接攔截器
- CallServerInterceptor:服務相應攔截器
3.OkHttp內部執(zhí)行流程介紹
同步請求流程:
當一次同步請求被執(zhí)行時炫掐,會先調用RealCall的excute方法
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
這個方法的作用是先對同步請求進行分發(fā),調用的Diapatcher的excuted方法睬涧,這個方法只是將請求緩存到dispatcher的runningSyncCalls的隊列集合中募胃,然后調用RealCall自己的getResponseWithInterceptorChain方法旗唁,這是整體OkHttp最為核心的方法,這個一個攔截器鏈摔认,它將一層層過濾請求逆皮,最終返回響應,然后在調用dispatcher的finished方法参袱,就是從runningSyncCalls隊列集合中將請求剔除电谣。這就是一次完整的okhttp的同步請求。
異步請求流程:
當一次異步請求被執(zhí)行時抹蚀,會先調用RealCall的enqueue方法
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
這個方法的作用時判斷這個請求是否已經(jīng)被執(zhí)行了剿牺,如果沒有被執(zhí)行,會將這個RealCall轉化成AsyncCall對象环壤,然后把他交給dispatcher類進行分發(fā)晒来,dispather對象中有兩個隊列集合跟異步請求有關系。
/** 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<>();
這兩個隊列集合從名字上就可以看出一個是準備去執(zhí)行的異步請求郑现,一個時正在執(zhí)行中的異步請求湃崩。dsipather的enqueue方法會對異步請求做進一步處理
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
這個方法的邏輯很清晰,如果超過最大任務數(shù)量64個接箫,或者同一個域名任務數(shù)5個攒读,它將進入準備隊列,反之將進入執(zhí)行隊列辛友,交由線程池執(zhí)行薄扁。因為AsyncCall繼承了NamedRunnable類,而NamedRunnable類實現(xiàn)了Runnable接口废累,所以最終的執(zhí)行方法在AsyncCall的execute的方法邓梅。
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
這個方法的邏輯的核心還是getResponseWithInterceptorChai這個方法,根據(jù)這個方法的返回回調Callback接口實現(xiàn)邑滨,然后在Dispatcher中的集合中剔除日缨。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
這個就是getResponseWithInterceptorChain的方法實現(xiàn),這個就是一個責任鏈設計的攔截器鏈驼修,每個攔截器層層處理殿遂。
以上就是okhttp內部的大致使用流程。