定義:Okhttp是對Socket的封裝。有三個主要的類,Request,Response,Call
默認使用new OkHttpClient() 創建初client對象。
如果需要初始化網絡請求的參數,如timeout,interceptor等,可以創建Builder,通過builder.build() 創建初client對象。
三個問題
1.請求發送到什么哪去了?框架里放到哪里了?
請求通過execute方法發送到框架中的兩個隊列中去了:運行中的隊列;等待中的隊列,如果說運行中的隊列總數小于64并且訪問同一目標機器請求小于5,就進入運行隊列,否則進入等待隊列
2.請求被誰處理:請求提交到運行中隊列后,交給線程池來處理,直接處理請求
3.請求是怎么被維護的:每次請求完成后,client.dispath調用finished方法,對運行中的隊列和等待中的隊列進行數據處理,(在符合條件的情況下,將等待中的加入到運行中隊列中去)
流程
1.通過
生成一個OkHttpClient client = new OkHttpClient();
2.構建一個Request requet = new Request.Builder()
.get().url("https:www.baidu.com").build();
3.通過client.newCall(request)得到Call,這個call是他的子類RealCall
4.通過call.execute(同步) 或call.enqueue(異步)啟動
A:執行Execute
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Execu
ted"); // (1)
executed = true;
}
try { client.dispatcher().executed(this);
// (2)
Response result = getResponseWithInterceptorChain();
// (3)
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this); // (4)
} }
1.先判斷這個call是否被執行了,每個call只能被執行一次,如果要一個完成一樣的call可以利用call的clone方法進行克隆
2.利用client.dispathcer().execute(this)來進行執行,其中dispatcher.execute方法為
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
這里我剛開始沒有相同,之后他加入隊列后怎么調用的,后來發現在 下一個方法調用的
3.調用getResponseWithInterceptorChain函數來獲取HTTP返回的結果,這里的originalRequest就是我們的請求剛剛加入隊列的是RealCall,通過chain.proceed(originalRequest)去調用
private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
4.最后還要通知dispathcer自己已經執行完畢
client.dispatcher().finished(this);
會執行finished(隊列、call,true)
其中這個方法是同步和異步都調用的方法,通過第三個參數,是否執行promoteCall方法具體的執行會不同,promoteCall方法
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
//TODO calls 移除隊列
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
//TODO 檢查是否為異步請求,檢查等候的隊列 readyAsyncCalls,如果存在等候隊列,則將等候隊列加入執行隊列
if (promoteCalls) promoteCalls();
//TODO 運行隊列的數量
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
//閑置調用
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
private void promoteCalls() {
//TODO 檢查 運行隊列 與 等待隊列
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
//TODO 將等待隊列加入到運行隊列中
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
//TODO 相同host的請求沒有達到最大,加入運行隊列
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
B執行Enqueue
// RealCall.java
@Override 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));
}
//TODO 執行異步請求
synchronized void enqueue(AsyncCall call) {
//TODO 同時請求不能超過并發數(64,可配置調度器調整)
//TODO okhttp會使用共享主機即 地址相同的會共享socket
//TODO 同一個host最多允許5條線程通知執行請求
if (runningAsyncCalls.size() < maxRequests &&
runningCallsForHost(call) < maxRequestsPerHost) {
//TODO 加入運行隊列 并交給線程池執行
runningAsyncCalls.add(call);
//TODO AsyncCall 是一個runnable,放到線程池中去執行,查看其execute實現
executorService().execute(call);
} else {
//TODO 加入等候隊列
readyAsyncCalls.add(call);
}
}