
前言
關(guān)于okhttp的介紹和同步請求,請看上一篇文章,個人筆記---Okhttp源碼跟蹤之同步,這里就不在贅述了,直接進入正題。
異步請求
/**
* 異步請求
*/
public void asyncCall(Callback callback) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://gank.io/api/today")
.build();
client.newCall(request).enqueue(callback);
}
異步請求時多了一個callback回調(diào),請求結(jié)果會在這個回調(diào)中返回。
前面創(chuàng)建call請求實例步驟和同步是一樣的,關(guān)鍵步驟就是異步調(diào)用的是enqueue方法,跟蹤一下這個方法。
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
異步也需要判斷當(dāng)前call請求是否已經(jīng)執(zhí)行過,邏輯和同步也是一樣的。然后又到了任務(wù)調(diào)度器的enqueue方法,并且傳入了一個AsyncCall實例,AsyncCall是RealCall的內(nèi)部類, 實現(xiàn)了Runnable接口,后續(xù)請求的時候會被放入線程池中,繼續(xù)跟蹤dispatcher的enqueue方法
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
首先會判斷當(dāng)前正在運行的異步隊列的大小是否小于了64(默認(rèn)支持最大并發(fā)送為64),單個host請求數(shù)是否小于5,滿足兩個條件,將請求加入runningAsyncCalls隊列,并且將call請求放入線程池執(zhí)行,如果任一條件不滿足,則將請求放入readyAsyncCalls等待隊列,等待隊列的邏輯會放在最后分析
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
如果線程池為空,則創(chuàng)建一個核心線程為0,最大線程為Integer.MAX_VALUE, 空閑線程存在的最大時間為60s的線程池,線程池創(chuàng)建完畢以后就開始執(zhí)行AsyncCall請求
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
AsyncCall這個內(nèi)部類在異步請求中還是比較重要的,它繼承了一個叫NamedRunnable的抽象類,當(dāng)線程運行時會調(diào)用execute這個抽象方法,因為AsyncCall是RealCall的內(nèi)部類,所以這個抽象方法的具體實現(xiàn)是在RealCall里面,繼續(xù)跟蹤
@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);
}
}
}
通過一系列的攔截器去獲取網(wǎng)絡(luò)請求結(jié)果,過程和同步是同樣的,關(guān)于攔截器的過程我會專門開一篇文章記錄,這里暫時不詳細(xì)說。
如果請求被取消則回調(diào)onFailure接口,未被取消則回調(diào)onResponse接口,我們可以看到回調(diào)的兩個方法并沒有切換線程,還是在子線程中,不能操作UI,當(dāng)前請求執(zhí)行完畢,調(diào)用dispatcher的finished方法
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();
}
}
將執(zhí)行完畢的請求從runningAsyncCalls隊列中移除,promoteCalls為異步標(biāo)志位,此時為true,會執(zhí)行到promoteCalls方法
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
如果此時請求數(shù)超過maxRequest數(shù)量,則直接return;若readyAsyncCalls等待隊列中沒有請求,則直接return;遍歷等待隊列,如果此時單個host請求數(shù)量小于5,將此請求從等待隊列移除并加入到runningAsyncCalls隊列中,將請求放入線程池中去執(zhí)行,執(zhí)行結(jié)束也會調(diào)用promoteCalls這個方法,直到readyAsyncCalls隊列為空,這樣就完成了所有請求。
至此,整個異步請求的過程也分析完成,因為能力有限,分析的比較粗略,只是對整個請求的流程梳理一下,后續(xù)會再深究一下其中的細(xì)節(jié)。
因水平有限,如有錯誤請指正,不勝感激!