OKHttp

定義: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);
        }
    }

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容