OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder().build();
Call newCall = okHttpClient.newCall(request);
//同步請求
//Response response = newCall.execute();
//異步請求
newCall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
複製代碼
public Response execute() throws IOException {
synchronized (this) {
//判斷當前call是否執行過,是的話拋異常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
//將當前call添加到Dispatcher正在執行的任務隊列
client.dispatcher().executed(this);
//經過一系列攔截器鏈作網絡請求,拿到response
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
//從正在執行的任務隊列中移除當前call
client.dispatcher().finished(this);
}
}
複製代碼
> RealCall類enqueue()方法
public void enqueue(Callback responseCallback) {
synchronized (this) {
//判斷當前call是否執行過,是的話拋異常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
複製代碼
判斷當前call是否執行過,是的話拋異常緩存
將callBack封裝成一個AsyncCall對象bash
> AsyncCall類execute()方法具體實現
protected void execute() {
boolean signalledCallback = false;
try {
//經過一系列攔截器鏈作網絡請求,拿到response
Response response = getResponseWithInterceptorChain();
//經過判斷重定向重試攔截器是否被取消了,是的話就調用responseCallback.onFailure()
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 {
//發生異常也會調用失敗回調
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//將當前請求call對象從正在運行任務隊列中移除
client.dispatcher().finished(this);
}
}
複製代碼
調用client.dispatcher().enqueue()服務器
> Dispatcher類enqueue()方法
//判斷正在運行異步任務隊列大小是否小於最大請求數(64)而且經過runningCallsForHost()方法獲取到正在運行的異步任務隊列中和當前call所要請求的主機同樣的調用數來判斷是否小於最大請求主機數(5)
//若是知足上述條件 則將當前call添加到正在運行異步任務隊列中,不然添加到等待異步任務隊列
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//添加到異步任務隊列
runningAsyncCalls.add(call);
//開啓線程池執行當前call
//executorService()方法內部會判斷線程池是否已經建立,是的話直接返回,否的話建立線程池
//execute() 未來某個時候執行給定的任務,任務能夠在新線程或現有池中已存在的線程執行
//其實就是把AsyncCall(線程的實現類)對象放到線程池中,最後真正執行的就是AsyncCall對象的execute()方法
executorService().execute(call);
} else {
//添加到異步等待任務隊列
readyAsyncCalls.add(call);
}
}
複製代碼
什麼是Dispatcher?網絡
dispatcher的做用是維護請求的狀態,並維護一個線程池,用於執行請求異步
Dispatcher的異步請求爲何要維護兩個任務隊列?ide
Dispatcher 生產者ui
ExecutorService 消費者池this
executorService()spa
public synchronized ExecutorService executorService() {
if (executorService == null) {
//corePoolSize:0 核心線程數.0的話就表示在空閒一段時間(keepAliveTime)後,會將所有線程銷燬
//maximumPoolSize:Integer.MAX_VALUE 線程池容許建立最大線程數;理論上設置MAX_VALUE能夠無限擴充建立線程,因爲OKHttp有maxRequests(64)限制,實際並不能無限建立線程
//keepAliveTime:60 空閒線程最大存活時間.當咱們的線程數大於核心線程數,多餘的空閒線程最大存活時間
//3個參數含義:當線程池中任務執行完畢以後,會在60秒以後相繼關閉全部空閒線程
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
複製代碼
移除任務call線程
同步請求和異步請求在拿到Response以後都會調用finished()方法
> 如下方法全是在Dispatcher類中
//異步請求
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
//同步請求
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) {
//從當前任務隊列中移除當前call
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
//調整異步請求任務隊列 只有異步請求才會執行promoteCalls()
if (promoteCalls) promoteCalls();
//從新計算正在執行任務數:異步請求+同步請求任務數量之和
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
/**
異步請求隊列從新調度.從等待隊列中移除一個任務,添加到正在執行異步隊列中
*/
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);
}
//若是正在執行異步隊列中數量大於等於最大請求數(64),直接結束調度
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
複製代碼
攔截器是OkHttp中提供一種強大機制,它能夠實現網絡監聽、請求以及響應重寫、請求失敗重試等功能
RetryAndFollowUpInterceptor
重試,失敗重定向攔截器
BridgeInterceptor
橋接適配攔截器,處理請求缺乏必要的http請求頭相關信息
CacheInterceptor
緩存攔截器,經過DiskLRUCache實現緩存存取,OkHttp內部維護清理線程池,會自動清理緩存文件
ConnectInterceptor
鏈接攔截器,創建可用的鏈接
newStream()總結
CallServerInterceptor