OkHttp執(zhí)行流程分析

本人通過源碼的解讀,只是為了加深對(duì)其執(zhí)行流程的理解,文章中不會(huì)對(duì)更細(xì)致的地方做過多的講解,只是把握住開源框架的整體脈絡(luò)。

首先放上一個(gè)簡(jiǎn)單使用的例子:

OkHttpClient client = new OkHttpClient.Builder().build();

Request request = new Request.Builder().url("http://www.baidu.com").build();

Call call = client.newCall(request);

//同步請(qǐng)求
try {
    Response response = call.execute();
    response.close();
} catch (IOException e) {
    e.printStackTrace();
}

//異步請(qǐng)求
call.enqueue(new Callback() {

    @Override
    public void onFailure(Call call, IOException e) {
        //todo failure
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        //todo response
    }
});

如上可以看到OkHttp有兩種數(shù)據(jù)請(qǐng)求方式:同步和異步,其中請(qǐng)求Call是一個(gè)接口,實(shí)際由RealCall執(zhí)行。

同步請(qǐng)求方式
public Response execute() throws IOException {
    ......

    Response var2;
    try {
        ...
        Response result = this.getResponseWithInterceptorChain();
        ...
        var2 = result;
    } catch (IOException var7) {
        this.eventListener.callFailed(this, var7);
        throw var7;
    } finally {
        this.client.dispatcher().finished(this);
    }

    return var2;
}

getResponseWithInterceptorChain是一個(gè)鏈?zhǔn)秸{(diào)用的一個(gè)方法,該方法是OkHttp的一個(gè)精華部分,暫且不講。
整個(gè)同步請(qǐng)求方式還是比較簡(jiǎn)單的,Call通過execute方法直接請(qǐng)求數(shù)據(jù),以及接受數(shù)據(jù)成功或者失敗的回調(diào)。

異步請(qǐng)求方式
// RealCall.java
public void enqueue(Callback responseCallback) {
    ......
    this.client.dispatcher().enqueue(new RealCall.AsyncCall(responseCallback));
}

// Dispatcher.java
/**
* 這里有個(gè)小細(xì)節(jié),異步請(qǐng)求不會(huì)是用多少請(qǐng)求就一定會(huì)立即會(huì)開始多少條請(qǐng)求,而是有個(gè)請(qǐng)求數(shù)量上限的。
* 只有執(zhí)行隊(duì)列的數(shù)量<最大請(qǐng)求數(shù),并且正在請(qǐng)求的host數(shù)<最大請(qǐng)求host數(shù)時(shí)才會(huì)請(qǐng)求,否則就暫時(shí)放在就緒隊(duì)列里緩存起來
*/
synchronized void enqueue(AsyncCall call) {
    if(this.runningAsyncCalls.size() < this.maxRequests 
        && this.runningCallsForHost(call) < this.maxRequestsPerHost) {
        this.runningAsyncCalls.add(call);
        this.executorService().execute(call);
    } else {
        this.readyAsyncCalls.add(call);
    }
}

final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    ......

    protected void execute() {
        boolean signalledCallback = false;

        try {
            // 1、請(qǐng)求結(jié)果
            Response response = RealCall.this.getResponseWithInterceptorChain();
            // 2、結(jié)果回調(diào)
            if(RealCall.this.retryAndFollowUpInterceptor.isCanceled()) {
                signalledCallback = true;
                this.responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
            } else {
                signalledCallback = true;
                this.responseCallback.onResponse(RealCall.this, response);
            }
        } catch (IOException var6) {
            // 3、失敗處理
            if(signalledCallback) {
                Platform.get().log(4, "Callback failure for " + RealCall.this.toLoggableString(), var6);
            } else {
                RealCall.this.eventListener.callFailed(RealCall.this, var6);
                this.responseCallback.onFailure(RealCall.this, var6);
            }
        } finally {
            // 4、結(jié)束
            RealCall.this.client.dispatcher().finished(this);
        }

    }
}

public abstract class NamedRunnable implements Runnable {

    public final void run() {
        ...
        this.execute();
        ...
    }

    protected abstract void execute();
}

如上流程可以看出,異步方式就是將RealCall通過包裝成AsyncCall,然后在線程池中進(jìn)行數(shù)據(jù)請(qǐng)求,然后執(zhí)行返回?cái)?shù)據(jù)成功或者失敗的處理。

通過以上的分析可以看出,OkHttp無論同步還是異步數(shù)據(jù)請(qǐng)求,整體的邏輯還是比較簡(jiǎn)單的,同步就直接在主線程中進(jìn)行數(shù)據(jù)請(qǐng)求,異步就是在異步線程池中進(jìn)行數(shù)據(jù)請(qǐng)求

無論同步還是異步請(qǐng)求,都有一個(gè)非常重要的一個(gè)方法:getResponseWithInterceptorChain(),這個(gè)方法也是OkHttp的精髓所在。下面具體開始分析該方法的實(shí)現(xiàn)。

getResponseWithInterceptorChain方法的實(shí)現(xiàn)邏輯分析
Response getResponseWithInterceptorChain() throws IOException {
    List<Interceptor> interceptors = new ArrayList();
    // 用戶自定義的攔截器列表
    interceptors.addAll(this.client.interceptors());
    interceptors.add(this.retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(this.client.cookieJar()));
    interceptors.add(new CacheInterceptor(this.client.internalCache()));
    interceptors.add(new ConnectInterceptor(this.client));
    if(!this.forWebSocket) {
        interceptors.addAll(this.client.networkInterceptors());
    }

    interceptors.add(new CallServerInterceptor(this.forWebSocket));
    // 注意第5個(gè)參數(shù)傳遞的是0
    Chain chain = new RealInterceptorChain(interceptors, (StreamAllocation)null, (HttpCodec)null, (RealConnection)null, 0, this.originalRequest, this, this.eventListener, this.client.connectTimeoutMillis(), this.client.readTimeoutMillis(), this.client.writeTimeoutMillis());
    return chain.proceed(this.originalRequest);
}

如上可以看出OkHttp除了用戶自定義的攔截器之外,主要包括如下幾個(gè)攔截器RetryAndFollowUpInterceptor、BridgeInterceptor、CacheInterceptor、ConnectInterceptor、NetworkInterceptor和CallServerInterceptor。這幾大攔截器共同組成了一個(gè)攔截器鏈,并封裝到RealInterceptorChain這個(gè)對(duì)象當(dāng)中。
既然是個(gè)攔截鏈,那OkHttp又是如何一條鏈一條鏈來進(jìn)行數(shù)據(jù)攔截的呢?
下面再看看它的proceed的實(shí)現(xiàn):

public Response proceed(Request request) throws IOException {
    return this.proceed(request, this.streamAllocation, this.httpCodec, this.connection);
}

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException {
    ...
    // 注意第5個(gè)參數(shù)為index+1
    RealInterceptorChain next = new RealInterceptorChain(this.interceptors, streamAllocation, httpCodec, connection, this.index + 1, request, this.call, this.eventListener, this.connectTimeout, this.readTimeout, this.writeTimeout);
    Interceptor interceptor = (Interceptor)this.interceptors.get(this.index);
    Response response = interceptor.intercept(next);
    ...
    return response;
}

這里大家只看到了其似乎只提取了一條攔截器,如何才能鏈?zhǔn)秸{(diào)用攔截器?這就是OkHttp設(shè)計(jì)的一個(gè)巧妙之處,正是通過interceptor.intercept(next)來不斷的獲取下一條攔截器進(jìn)行數(shù)據(jù)攔截,然后返回最終的response。
Intercepter是一個(gè)接口,這里我拿RetryAndFollowUpInterceptor舉例:

public Response intercept(Chain chain) throws IOException {
    ......
    RealInterceptorChain realChain = (RealInterceptorChain)chain;
    response = realChain.proceed(request, this.streamAllocation, (HttpCodec)null, (RealConnection)null);
    ......
    return response;
}

看到?jīng)]有,類似這個(gè)攔截器一樣,每個(gè)攔截器都會(huì)最終調(diào)用realChain.proceed來不斷獲取下一個(gè)攔截器對(duì)返回?cái)?shù)據(jù)進(jìn)行攔截處理,從而最終得到處理后成功或者失敗的數(shù)據(jù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 用OkHttp很久了,也看了很多人寫的源碼分析,在這里結(jié)合自己的感悟,記錄一下對(duì)OkHttp源碼理解的幾點(diǎn)心得。 ...
    藍(lán)灰_q閱讀 4,531評(píng)論 4 34
  • 那么我今天給大家簡(jiǎn)單地講一下Okhttp這款網(wǎng)絡(luò)框架及其原理。它是如何請(qǐng)求數(shù)據(jù),如何響應(yīng)數(shù)據(jù)的 有什么優(yōu)點(diǎn)?它的應(yīng)...
    卓而不群_0137閱讀 348評(píng)論 0 1
  • 1、概述 okhttp是一個(gè)第三方類庫,用于android中請(qǐng)求網(wǎng)絡(luò)。同時(shí)這是一個(gè)開源項(xiàng)目,用來替代HttpUrl...
    高丕基閱讀 2,626評(píng)論 0 15
  • OkHttp源碼分析 在現(xiàn)在的Android開發(fā)中,請(qǐng)求網(wǎng)絡(luò)獲取數(shù)據(jù)基本上成了我們的標(biāo)配。在早期的Android開...
    BlackFlag閱讀 414評(píng)論 0 5
  • 2017-10-25奧克蘭薩維奇紀(jì)念公園、維多利亞山。
    朱平閱讀 167評(píng)論 0 0

友情鏈接更多精彩內(nèi)容