OkHttp原理解析1(框架流程篇)

OkHttp3.png

一直想寫(xiě)一篇 簡(jiǎn)潔而不失內(nèi)涵 的OKHTTP源碼分析获雕,甚至從19年春節(jié)前就開(kāi)始翻閱OkHttp的源碼雕欺。但是趕上春節(jié)事多心雜岛马,沒(méi)能將心中所想梳理出來(lái)。
現(xiàn)在疫情當(dāng)前屠列,節(jié)約了外出活動(dòng)的時(shí)間啦逆,靜心打磨了此文,希望對(duì)看本文的小伙伴有所幫助笛洛,更希望 武漢堅(jiān)強(qiáng)夏志,祖國(guó)安康

本文源碼基于OkHttp3.14.6苛让,該版本是Java版最新的一版沟蔑,后續(xù)的4.*全面使用了Kotlin,如有需要可再進(jìn)行分析。

針對(duì)OkHttp我打算開(kāi)兩篇進(jìn)行分析蝌诡。

第1篇分析整體的框架設(shè)計(jì)溉贿,以及大方向的請(qǐng)求流程枫吧。
第2篇分析具體攔截器的功能邏輯浦旱。

好,我們開(kāi)始表演九杂。

在翻看源碼之前颁湖,對(duì)OkHttp的了解只停留在使用層面宣蠕,對(duì)Api使用非常的6。完全沒(méi)關(guān)心過(guò)內(nèi)部原理甥捺。更別提設(shè)計(jì)思想了抢蚀。
有句 德瑪西亞 名言咋說(shuō)來(lái)著 新手拼的是英雄,技能镰禾,熟練度皿曲。高玩靠的是走位,意識(shí)吴侦,英雄池屋休。
這句話你品,你細(xì)品~~~

本文爭(zhēng)取以一個(gè)高玩的姿態(tài)去解讀OkHttp的源碼备韧,至于有多高呢劫樟?
嗯~~~ 還是這么高。织堂。叠艳。


image.png

我們?cè)倏丛创a的時(shí)候有一個(gè)技巧,不一定非要挨個(gè)類去逐行閱讀易阳,枯燥無(wú)味不說(shuō)附较,關(guān)鍵是很難和功能相對(duì)應(yīng),可根據(jù)使用方式切入潦俺,根據(jù)邏輯調(diào)用鏈翅睛,層層跟進(jìn)。
本文呢又是一篇深入淺出的題材黑竞,還是那迷人的姿勢(shì)捕发,還是那熟悉的套路。
從使用到原理很魂,從架構(gòu)到邏輯扎酷。
使用體現(xiàn)的是框架的能力,架構(gòu)承載的是框架的靈魂遏匆。
我們將從以下幾個(gè)問(wèn)題出發(fā)法挨,循循漸進(jìn),層層深入幅聘。

    1. OkHttp有什么優(yōu)勢(shì)凡纳?為啥要分析的是OkHttp而不是其他框架?
    1. OkHttp的使用方式有哪些?
    1. OkHttp的架構(gòu)是什么樣的帝蒿?
    1. OkHttp的內(nèi)部是咋實(shí)現(xiàn)的荐糜?

1. OkHttp有什么優(yōu)勢(shì)?為啥要分析的是OkHttp而不是其他框架?

其實(shí)Android的網(wǎng)絡(luò)框架有很多,比如Android-Async-Http暴氏,Volley延塑,OkHttp,Retrofit答渔,那為啥偏要分析OkHttp呢关带?因?yàn)樗鼘虐~~
我們先看一個(gè)這個(gè)對(duì)比圖就明白了。

對(duì)比分析 Android-Async-Http volley OkHttp Retrofit
技術(shù)分析 基于HttpClient 基于HttpUrlConnection 基于Socket沼撕, 和HttpUrlConnection同級(jí)但并不屬于HttpUrlConnection 基于Okhttp
優(yōu)勢(shì) 自動(dòng)智能請(qǐng)求重試 ;持久化cookie存儲(chǔ) 1.支持圖片加載;網(wǎng)絡(luò)請(qǐng)求的排序宋雏。
2.優(yōu)先級(jí)處理緩存。
3.多級(jí)別取消請(qǐng)求务豺。
4.生命周期控制好芭,退出后自動(dòng)取消請(qǐng)求。
5.可拓展性好;可支持HttpClient冲呢、HttpUrlConnection舍败、和OkHttp
1.高性能Http請(qǐng)求庫(kù)。
2.支持SPDY敬拓,共享同一個(gè)Socket來(lái)處理同一個(gè)服務(wù)器所有的請(qǐng)求.
3.支持http2.0邻薯、websocket;支持同步、異步乘凸。
4.內(nèi)部封裝了線程池厕诡、數(shù)據(jù)轉(zhuǎn)換、參數(shù)使用营勤、錯(cuò)誤處理等灵嫌。
5.支持GZIP來(lái)減少數(shù)據(jù)流量鼻百。
6.基于NIO和OKio,性能更高袱讹。
1.Api牛逼
2.支持通過(guò)注解配置參數(shù)烦感,url等信息柏肪。
3.支持Gson,Jackson望伦,Protobuf纳猫。
4.支持RxJava蓖扑。
5.代碼簡(jiǎn)化;解耦徹底虱岂。
劣勢(shì) Android5.0之后不推薦用HttpClient 玖院,并且該框架通知維護(hù)。 Volley的Request和Response都是把數(shù)據(jù)放到byte數(shù)組里第岖,不支持輸入輸出流难菌,把數(shù)據(jù)放到數(shù)組中,如果文件多了蔑滓,數(shù)組就會(huì)大郊酒,消耗內(nèi)存 ... ...

目前相對(duì)主流的框架Retrofit遇绞,Glide中都是內(nèi)置了OkHttp,而Retrift自己即是網(wǎng)絡(luò)框架猎塞,且它都基于OkHttp试读,可見(jiàn)OkHttp是怎樣一個(gè)地位杠纵。

2. OkHttp的使用方式有哪些荠耽?

接下來(lái)將秀8種操作,看好了您嘞比藻。

  • 1.同步Get請(qǐng)求
  • 2.異步Get請(qǐng)求
  • 3.同步Post請(qǐng)求
  • 4.異步Post請(qǐng)求
  • 5.Post提交文件
  • 6.Post提交from表單
  • 7.文件字符串復(fù)合提交
  • 8.攔截器使用

/**
  * 1.同步Get請(qǐng)求
  * 2.異步Get請(qǐng)求
  * 3.同步Post請(qǐng)求
  * 4.異步Post請(qǐng)求
  * 5.Post提交文件
  * 6.Post提交from表單
  * 7.文件字符串復(fù)合提交
  * 8.攔截器使用
  */

  OkHttpClient okHttpClient = new OkHttpClient();

    /**
     * 同步Get請(qǐng)求
     */
    private void SyncGet() {
        try {
            Request request = new Request.Builder()
                    .url("url")
                    .build();
            Call call = okHttpClient.newCall(request);
            Response response = call.execute();
        } catch (Exception e) {

        }

    }

    /**
     * 異步Gost請(qǐng)求
     */
    private void AsyncGet() {
        Request request = new Request.Builder()
                .url("url")
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請(qǐng)求失敗
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請(qǐng)求成功
            }
        });

    }

    /**
     * 同步Post請(qǐng)求
     */
    private void SyncPost() {
        try {
            MediaType JSON = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
            String str = "通信數(shù)據(jù)";
            Request request = new Request.Builder().url("url").post(RequestBody.create(JSON, str)).build();
            Call call = okHttpClient.newCall(request);
            Response response = call.execute();
        } catch (Exception e) {

        }

    }

    /**
     * 異步Post請(qǐng)求
     */
    private void AsyncPost() {
        MediaType JSON = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
        String str = "通信數(shù)據(jù)";
        Request request = new Request.Builder().url("url").post(RequestBody.create(JSON, str)).build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請(qǐng)求失敗
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請(qǐng)求成功
            }
        });
    }

    private void postFile() {
        MediaType fileMediaType = MediaType.parse("text/x-markdown; charset=utf-8");
        Request request = new Request.Builder()
                .url("url")
                .post(RequestBody.create(fileMediaType, new File("sd/mnt/a.png")))
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請(qǐng)求失敗
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請(qǐng)求成功
            }
        });
    }

    /**
     * Post提交from表單
     */
    private void postFrom() {
        MediaType fileMediaType = MediaType.parse("text/x-markdown; charset=utf-8");
        Request request = new Request.Builder()
                .url("url")
                .post(new FormBody.Builder().add("key", "value").build())
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請(qǐng)求失敗
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請(qǐng)求成功
            }
        });
    }

  /**
     * Post提交組合數(shù)據(jù)(字符串+文件)
     */
    private void postMultipartBody() {
        MediaType fileMediaType = MediaType.parse("image/png");
        RequestBody requestBody = RequestBody.create(fileMediaType, new File("sd/mnt/1.png"));
        MultipartBody multipartBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"title\""),
                        RequestBody.create(null, "文字")//這樣可以直接添加數(shù)據(jù)铝量,無(wú)需單獨(dú)創(chuàng)建RequestBody
                )
                .addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"image\""),
                        RequestBody.create(fileMediaType, new File("sd/mnt/1.png"))//這樣可以直接添加文件,無(wú)需單獨(dú)創(chuàng)建RequestBody
                )
                .addFormDataPart("key", "value")//添加表單數(shù)據(jù)
                .addFormDataPart("file", "fileName", requestBody)
                .build();
        Request request = new Request.Builder()
                .url("url")
                .post(multipartBody)
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請(qǐng)求失敗
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請(qǐng)求成功
            }
        });
    }


    /**
     * 使用攔截器
     */
    private void postAndInterceptor() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new MyInterceptor())
                .build();
        MediaType fileMediaType = MediaType.parse("image/png");
        RequestBody requestBody = RequestBody.create(fileMediaType, new File("sd/mnt/1.png"));
        MultipartBody multipartBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("key", "value")//添加表單數(shù)據(jù)
                .addFormDataPart("file", "fileName", requestBody)
                .build();
        Request request = new Request.Builder()
                .url("url")
                .post(multipartBody)
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請(qǐng)求失敗
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請(qǐng)求成功
            }
        });
    }

    /**
     * 攔截器
     */
    public class MyInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            Log.d("TAG", "請(qǐng)求返回?cái)?shù)據(jù)為:" + response.body().string());

            return null;
        }
    }
3. OkHttp的架構(gòu)是什么樣的银亲?

這個(gè)問(wèn)題挺深入慢叨,唯有此圖以示天下。

整體架構(gòu)圖.png

上圖主要以執(zhí)行流程來(lái)劃分务蝠,其主要涉及的類包含以下幾個(gè)

  • OkHttpClient 客戶端對(duì)象
  • OkHttpClient.Builder 以構(gòu)件者模式創(chuàng)建OkHttpClient對(duì)象
  • Request 請(qǐng)求對(duì)象
    • HttpUrl url; 請(qǐng)求對(duì)象參數(shù)
    • String method;請(qǐng)求對(duì)象參數(shù)
    • Headers.Builder headers;請(qǐng)求對(duì)象參數(shù)
    • RequestBody body;請(qǐng)求對(duì)象參數(shù)
    • Map<Class<?>, Object> tags = Collections.emptyMap();請(qǐng)求對(duì)象參數(shù)
  • Request.Builder 構(gòu)建者模式用于創(chuàng)建Request
  • Response 請(qǐng)求結(jié)果對(duì)象拍谐。
    • Request request;返回對(duì)象參數(shù)
    • Protocol protocol;返回對(duì)象參數(shù)
    • int code;返回對(duì)象參數(shù)
    • String message;返回對(duì)象參數(shù)
    • Handshake handshake;返回對(duì)象參數(shù)
    • Headers headers;返回對(duì)象參數(shù)
    • ResponseBody body;返回對(duì)象參數(shù)
    • Response networkResponse;返回對(duì)象參數(shù)
    • Response cacheResponse;返回對(duì)象參數(shù)
    • Response priorResponse;返回對(duì)象參數(shù)
    • long sentRequestAtMillis;返回對(duì)象參數(shù)
    • long receivedResponseAtMillis;返回對(duì)象參數(shù)
    • Exchange exchange;返回對(duì)象參數(shù)
  • RealCall implements Call 請(qǐng)求控制器,用于執(zhí)行request
  • Dispatcher 調(diào)度器馏段,主要用于請(qǐng)求的策略處理轩拨。
  • AsyncCall是一個(gè)Runnable,線程池調(diào)用院喜。
  • Callback 接收回調(diào)使用
  • Interceptor 攔截器接口亡蓉,所有的攔截器均實(shí)現(xiàn)該接口,責(zé)任鏈模式的每一個(gè)攔截器接口喷舀。
4. OkHttp的內(nèi)部是咋實(shí)現(xiàn)的砍濒?

又到了你么最喜歡的講道理擺姿勢(shì)的環(huán)節(jié)了。
分析OkHttp的內(nèi)部實(shí)現(xiàn)可以從使用角度出發(fā)硫麻,以使用邏輯分析框架入口爸邢,然后層層跟進(jìn)。我們以普通的get請(qǐng)求為例拿愧,主要涉及以下幾個(gè)入口甲棍。

  • 1. OkHttpClient okHttpClient = new OkHttpClient();

  • 2. Request request = new Request.Builder().url("url").build();

  • 3. Call call = okHttpClient.newCall(request);

  • 4. call.enqueue(new Callback() {... });

我們逐個(gè)分析一下。
4.1. OkHttpClient okHttpClient = new OkHttpClient();內(nèi)部執(zhí)行了哪些邏輯赶掖?我們看下源碼

//OkHttpClient的構(gòu)造函數(shù)
public OkHttpClient() {
    this(new Builder());
  }
//OkHttpClient的構(gòu)造函數(shù)
  OkHttpClient(Builder builder) {
    this.dispatcher = builder.dispatcher;
    this.proxy = builder.proxy;
    this.protocols = builder.protocols;
    this.connectionSpecs = builder.connectionSpecs;
    this.interceptors = Util.immutableList(builder.interceptors);
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
    this.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;

    boolean isTLS = false;
    for (ConnectionSpec spec : connectionSpecs) {
      isTLS = isTLS || spec.isTls();
    }

    if (builder.sslSocketFactory != null || !isTLS) {
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
      X509TrustManager trustManager = Util.platformTrustManager();
      this.sslSocketFactory = newSslSocketFactory(trustManager);
      this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
    }

    if (sslSocketFactory != null) {
      Platform.get().configureSslSocketFactory(sslSocketFactory);
    }

    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.callTimeout = builder.callTimeout;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;

    if (interceptors.contains(null)) {
      throw new IllegalStateException("Null interceptor: " + interceptors);
    }
    if (networkInterceptors.contains(null)) {
      throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
    }
  }
    //OkHttpClient 中靜態(tài)內(nèi)部類Builder的構(gòu)造方法
    public Builder() {
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();
      if (proxySelector == null) {
        proxySelector = new NullProxySelector();
      }
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();
      dns = Dns.SYSTEM;
      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;
      callTimeout = 0;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
      pingInterval = 0;
    }
  //OkHttpClient 中靜態(tài)內(nèi)部類Builder的構(gòu)造方法
    Builder(OkHttpClient okHttpClient) {
      this.dispatcher = okHttpClient.dispatcher;
      this.proxy = okHttpClient.proxy;
      this.protocols = okHttpClient.protocols;
      this.connectionSpecs = okHttpClient.connectionSpecs;
      this.interceptors.addAll(okHttpClient.interceptors);
      this.networkInterceptors.addAll(okHttpClient.networkInterceptors);
      this.eventListenerFactory = okHttpClient.eventListenerFactory;
      this.proxySelector = okHttpClient.proxySelector;
      this.cookieJar = okHttpClient.cookieJar;
      this.internalCache = okHttpClient.internalCache;
      this.cache = okHttpClient.cache;
      this.socketFactory = okHttpClient.socketFactory;
      this.sslSocketFactory = okHttpClient.sslSocketFactory;
      this.certificateChainCleaner = okHttpClient.certificateChainCleaner;
      this.hostnameVerifier = okHttpClient.hostnameVerifier;
      this.certificatePinner = okHttpClient.certificatePinner;
      this.proxyAuthenticator = okHttpClient.proxyAuthenticator;
      this.authenticator = okHttpClient.authenticator;
      this.connectionPool = okHttpClient.connectionPool;
      this.dns = okHttpClient.dns;
      this.followSslRedirects = okHttpClient.followSslRedirects;
      this.followRedirects = okHttpClient.followRedirects;
      this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure;
      this.callTimeout = okHttpClient.callTimeout;
      this.connectTimeout = okHttpClient.connectTimeout;
      this.readTimeout = okHttpClient.readTimeout;
      this.writeTimeout = okHttpClient.writeTimeout;
      this.pingInterval = okHttpClient.pingInterval;
    }
//通過(guò)靜態(tài)內(nèi)部類Builder的build()方法可創(chuàng)建 OkHttpClient 對(duì)象感猛。
 public OkHttpClient build() {
      return new OkHttpClient(this);
    }

我們分析下這一大段代碼,其實(shí)邏輯內(nèi)容非常簡(jiǎn)單奢赂,主要干了這么幾件事陪白。

    1. 設(shè)置了緩存、線程池膳灶、攔截器咱士,超時(shí)等變量數(shù)據(jù)立由。
    1. OkHttpClient使用了構(gòu)建者模式。
    1. new OkHttpClient()內(nèi)部實(shí)際調(diào)用的是 new OkHttpClient(new Builder())序厉。
    1. OkHttpClient還可通過(guò)new OkHttpClient.Builder().build();創(chuàng)建OkHttpClient對(duì)象锐膜。
  • 5.為什么要使用構(gòu)建者模式?當(dāng)一個(gè)類的內(nèi)部數(shù)據(jù)過(guò)于復(fù)雜的時(shí)候弛房,要?jiǎng)?chuàng)建的話可能就需要了解這個(gè)類的內(nèi)部結(jié)構(gòu)以及相互關(guān)系等等道盏。會(huì)大大提升框架的使用成本,因此創(chuàng)建的時(shí)候會(huì)有一個(gè)名為Builder的內(nèi)部類模板文捶,設(shè)置好了默認(rèn)的值和邏輯關(guān)系荷逞。這種模板可以有多個(gè),使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的對(duì)象粹排。使用戶不了解內(nèi)部邏輯的情況下也可以正常創(chuàng)建對(duì)象种远。大大降低的使用成本。

4.2. Request request = new Request.Builder().url("url").build();內(nèi)部又干了啥顽耳?
從寫(xiě)法上看坠敷,Request 一樣也使用了構(gòu)建者模式,我們分開(kāi)Request.Builder()射富,url("url")膝迎,build()一個(gè)一個(gè)看。

//Request構(gòu)造函數(shù)
Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tags = Util.immutableMap(builder.tags);
  }
//Request的靜態(tài)內(nèi)部類Builder構(gòu)造函數(shù)
 public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }
  //Request的靜態(tài)內(nèi)部類Builder構(gòu)造函數(shù)
    Builder(Request request) {
      this.url = request.url;
      this.method = request.method;
      this.body = request.body;
      this.tags = request.tags.isEmpty()
          ? Collections.emptyMap()
          : new LinkedHashMap<>(request.tags);
      this.headers = request.headers.newBuilder();
    }
  //Request的靜態(tài)內(nèi)部類Builder設(shè)置url方法
    public Builder url(HttpUrl url) {
      if (url == null) throw new NullPointerException("url == null");
      this.url = url;
      return this;
    }

    /**
     *  Request的靜態(tài)內(nèi)部類Builder設(shè)置url方法
     *
     * @如果url是無(wú)效的則拋出 throws IllegalArgumentException  通過(guò)調(diào)用HttpUrl.get(url)避免這種異常辉浦,
     * 無(wú)效的url返回null
     */
    public Builder url(String url) {
      if (url == null) throw new NullPointerException("url == null");

      // Silently replace web socket URLs with HTTP URLs.
      if (url.regionMatches(true, 0, "ws:", 0, 3)) {
        url = "http:" + url.substring(3);
      } else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
        url = "https:" + url.substring(4);
      }

      return url(HttpUrl.get(url));
    }

    /**
     * Request的靜態(tài)內(nèi)部類Builder設(shè)置url方法
     *
     * @throws IllegalArgumentException if the scheme of {@code url} is not {@code http} or {@code
     * https}.
     */
    public Builder url(URL url) {
      if (url == null) throw new NullPointerException("url == null");
      return url(HttpUrl.get(url.toString()));
    }

    // Request的靜態(tài)內(nèi)部類Builder設(shè)置build方法
    public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }

我們總結(jié)下 new Request.Builder().url("url").build()干了幾件事弄抬。

    1. 通過(guò)new Request.Builder()構(gòu)造者模式設(shè)置了默認(rèn)的請(qǐng)求方式GET,且通過(guò)headers的構(gòu)建者創(chuàng)建了 headers宪郊。
    1. url()方法使用到了面向?qū)ο笾剌d的方法掂恕,入?yún)⒅С諬ttpUrl 、String 弛槐、URL三種類型懊亡。最終目的即是設(shè)置請(qǐng)求地址。
    1. .build()則通過(guò)以上設(shè)置的屬性調(diào)用Request構(gòu)造函數(shù)乎串,創(chuàng)建Request對(duì)象店枣。

4.3. Call call = okHttpClient.newCall(request);又是干什么的呢?
以上的4.1 , 4.2均是為了創(chuàng)建okHttpClient叹誉,Request對(duì)象鸯两,以及初始化一數(shù)據(jù),并沒(méi)有進(jìn)行其他操作长豁。
okHttpClient.newCall(request);又做了什么操作呢钧唐?

 /**
   * okHttpClient的newCall()
   * 準(zhǔn)備request,將在某個(gè)時(shí)間執(zhí)行匠襟。 
   */
  @Override public Call newCall(Request request) {
     //最后這個(gè)參數(shù)是否為web socket默認(rèn)傳false
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
 /**
   *RealCall.newRealCall(...)
   *實(shí)例化RealCall對(duì)象钝侠,初始化RealCall.transmitter该园。
   */
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.transmitter = new Transmitter(client, call);
    return call;
  }
 /**
   *RealCall(...)
   */
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
  }
 /**
   *Transmitter類構(gòu)造函數(shù) 。
   */
public Transmitter(OkHttpClient client, Call call) {
    this.client = client;
    this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());
    this.call = call;
    this.eventListener = client.eventListenerFactory().create(call);
    this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
  }

總結(jié):這一堆居然還是在創(chuàng)建對(duì)象帅韧,真正的請(qǐng)求還沒(méi)有開(kāi)始里初。

    1. 通過(guò)okHttpClient.newCall()調(diào)用了RealCall.newRealCall()并把Request,okHttpClient作為參數(shù)傳過(guò)去。
    1. RealCall.newRealCall()中通過(guò)構(gòu)造函數(shù)創(chuàng)建了RealCall和Transmitter對(duì)象忽舟。
  • 3.Transmitter主要用于設(shè)置連接池双妨,事件監(jiān)聽(tīng)器,以及超時(shí)等待時(shí)間萧诫。
    • 3.1. 注意Transmitter中這句 Internal.instance.realConnectionPool(client.connectionPool()); Internal.instance只在OkHttpClient有實(shí)現(xiàn)斥难,因此也只會(huì)調(diào)用OkHttpClient中的實(shí)現(xiàn)接口枝嘶,目的是拿到connectionPool連接池帘饶。
    • 3.2. client.eventListenerFactory()獲取的EventListener.Factory其實(shí)是在OkHttpClient的Builder()中通過(guò) EventListener.factory(EventListener.NONE);創(chuàng)建的。默認(rèn)傳的EventListener是一個(gè)空的群扶。

4.4. call.enqueue(new Callback() {... });應(yīng)該開(kāi)始請(qǐng)求了吧...
前邊準(zhǔn)備的所有準(zhǔn)備均為了最后這一步請(qǐng)求及刻,我們看下邏輯是怎么操作的。

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    transmitter.callStart();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
//transmitter.callStart();
public void callStart() {
    this.callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
    eventListener.callStart(call);
  }

這塊有點(diǎn)復(fù)雜我們一點(diǎn)一點(diǎn)的分析竞阐,最后進(jìn)行總結(jié)缴饭。
首先call.enqueue()中進(jìn)行了執(zhí)行狀態(tài)賦值,防止重復(fù)執(zhí)行請(qǐng)求骆莹。
其次調(diào)用了transmitter.callStart();啟動(dòng)堆棧的跟蹤颗搂,以及eventListener的一些回調(diào)處理。
最后即是最關(guān)鍵的異步 client.dispatcher().enqueue(new AsyncCall(responseCallback));是真正的請(qǐng)求流程幕垦。
我繼續(xù)深入分析

//Dispatcher.enqueue()
void enqueue(AsyncCall call) {
    synchronized (this) {
      //readyAsyncCalls是一個(gè)準(zhǔn)備調(diào)用的AsyncCall隊(duì)列
      readyAsyncCalls.add(call);

      // 如果不是WebSocket丢氢,將通過(guò)call.host查找是否有運(yùn)行中的AsyncCall ,如果有將通過(guò)AtomicInteger類型共享到當(dāng)前 AsyncCall 對(duì)象中先改。
      if (!call.get().forWebSocket) {
        AsyncCall existingCall = findExistingCallWithHost(call.host());
        //異步請(qǐng)求疚察,OkHttp會(huì)對(duì)有相同主機(jī)的call在請(qǐng)求時(shí)進(jìn)行記數(shù),通過(guò)AtomicInteger對(duì)象進(jìn)行即時(shí)同步仇奶。
        //這個(gè)計(jì)數(shù)對(duì)后續(xù)的請(qǐng)求有影響貌嫡,我們后邊再詳細(xì)分析。
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
      }
    }
    //真正執(zhí)行操作
    promoteAndExecute();
  }
//循環(huán)runningAsyncCalls和readyAsyncCalls隊(duì)列
  @Nullable private AsyncCall findExistingCallWithHost(String host) {
    for (AsyncCall existingCall : runningAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    for (AsyncCall existingCall : readyAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    return null;
  }
/**
   *readyAsyncCalls中滿足條件的對(duì)象移動(dòng)到runningAsyncCalls中 并且在 executor service上運(yùn)行该溯。 
   * 必須同步調(diào)用岛抄,因?yàn)橐卣{(diào)用戶的代碼
   *
   * 如果調(diào)度程序當(dāng)前正在運(yùn)行,則返回true
   */
  private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));

    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      //循環(huán)readyAsyncCalls隊(duì)列狈茉。
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();
        //如果運(yùn)行隊(duì)列runningAsyncCalls超過(guò)了maxRequests直接break夫椭。(默認(rèn)值為64)
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        //如果當(dāng)前的主機(jī)計(jì)數(shù)器>5則continue,這個(gè)計(jì)數(shù)器就是上述enqueue()方法的計(jì)數(shù)器论皆。
        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
        從readyAsyncCalls中移除
        i.remove();
        //相同主機(jī)的asyncCall計(jì)數(shù)器+1
        asyncCall.callsPerHost().incrementAndGet();
        executableCalls.add(asyncCall);
        //添加到runningAsyncCalls隊(duì)列中
        runningAsyncCalls.add(asyncCall);
      }
      //運(yùn)行狀態(tài)賦值益楼,異步/同步只要有一個(gè)在運(yùn)行則為true猾漫。
      isRunning = runningCallsCount() > 0;
    }

    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
     //開(kāi)始運(yùn)行,具體的運(yùn)行邏輯我們后續(xù)分析感凤。
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }

ok悯周,我們總結(jié)下Dispatcher.enqueue()干了什么事

    1. 將AsyncCall添加到準(zhǔn)備隊(duì)列readyAsyncCalls。
    1. 通過(guò)AsyncCall對(duì)象查找runningAsyncCalls和readyAsyncCalls隊(duì)列中是否想相同主機(jī)的AsyncCall陪竿,如果有則通過(guò)AtomicInteger對(duì)象將AsyncCall.callsPerHost引用到一起禽翼,方便后續(xù)的計(jì)數(shù)統(tǒng)計(jì)。
    1. 調(diào)用promoteAndExecute()循環(huán)readyAsyncCalls隊(duì)列族跛,判斷runningAsyncCalls隊(duì)列大于64或asyncCall.callsPerHost>5均終止添加到runningAsyncCalls隊(duì)列中闰挡。
    1. asyncCall.callsPerHost計(jì)數(shù)器+1,AsyncCall添加到runningAsyncCalls隊(duì)列中礁哄,從readyAsyncCalls中移除长酗。啟動(dòng)for循環(huán)調(diào)用 asyncCall.executeOn(executorService());進(jìn)行請(qǐng)求。

asyncCall.executeOn(executorService());中又干了啥桐绒?

//Dispatcher.executorService()
//如果executorService 為null則創(chuàng)建一個(gè)ThreadPoolExecutor線程池
public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

/**
    * AsyncCall.executeOn()
     * 嘗試通過(guò) executorService啟動(dòng)執(zhí)行AsyncCall
     * 如果 executor已經(jīng)關(guān)閉了則嘗試清楚夺脾,并報(bào)失敗
     */
    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
        //線程池執(zhí)行AsyncCall
        executorService.execute(this);
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        transmitter.noMoreExchanges(ioException);
        //回調(diào)onFailure
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        if (!success) {
          //如果沒(méi)成功,調(diào)用OkHttpClient.dispatcher().finished(this);
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }

/**
  * Dispatcher.finished()
  *失敗
  */
  void finished(AsyncCall call) {
    //AsyncCall 中相同主機(jī)計(jì)數(shù)器-1茉继。
    call.callsPerHost().decrementAndGet();
    finished(runningAsyncCalls, call);
  }
//Dispatcher.finished(...)
private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
      //從runningAsyncCalls中移除call咧叭。
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      idleCallback = this.idleCallback;
    }
    //重新調(diào)用promoteAndExecute()
    boolean isRunning = promoteAndExecute();

    if (!isRunning && idleCallback != null) {
      //如果同步異步均沒(méi)有運(yùn)行了并且idleCallback 不為空 則通知當(dāng)前為空閑狀態(tài)了。
      idleCallback.run();
    }
  }

我們?cè)倏偨Y(jié)下asyncCall.executeOn(executorService())到底干了啥烁竭。

    1. 通過(guò)executorService()創(chuàng)建了一個(gè)ThreadPoolExecutor線程池菲茬。
    1. 啟動(dòng)了executorService線程池。
    1. 如果線程池出現(xiàn)了異常則啟動(dòng)異常處理派撕,通過(guò) responseCallback回調(diào)onFailure
    1. 通過(guò)finally 關(guān)鍵字判斷如果本次請(qǐng)求失敗了則調(diào)用OkHttpClient.dispatcher().finished(this)
    • 4.1. AsyncCall.callsPerHost 相同主機(jī)計(jì)數(shù)器-1婉弹。
    • 4.2 . 從runningAsyncCalls中移除當(dāng)前AsyncCall并重新調(diào)用promoteAndExecute()。
    • 4.3 . 如果同步異步均沒(méi)有運(yùn)行了并且idleCallback 不為空 則通知當(dāng)前為空閑狀態(tài)了腥刹。
    1. executorService.execute(this);證明其實(shí)this為AsyncCall马胧,類型為Runnable。

executorService.execute(this);是執(zhí)行請(qǐng)求的邏輯內(nèi)容衔峰,我們?cè)敿?xì)看下
executorService是一個(gè)線程池佩脊,而this代表的是AsyncCall這個(gè)類,現(xiàn)在其實(shí)可以發(fā)現(xiàn)AsyncCall實(shí)際上繼承的是NamedRunnable垫卤,而NamedRunnable實(shí)現(xiàn)了Runnable威彰,這下就簡(jiǎn)單了,我們直接找Runnable的run方法即可穴肘。

public abstract class NamedRunnable implements Runnable {
...
  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      //主要執(zhí)行了這個(gè)方法歇盼,這個(gè)方法實(shí)際是一個(gè)抽象方法,需要看實(shí)現(xiàn)類的實(shí)現(xiàn)评抚。
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }
  protected abstract void execute();
}

//AsyncCall.execute()
@Override 
protected void execute() {
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
        Response response = getResponseWithInterceptorChain();
        signalledCallback = true;
        //回調(diào)結(jié)果
        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);
        }
      } catch (Throwable t) {
        cancel();
        if (!signalledCallback) {
          IOException canceledException = new IOException("canceled due to " + t);
          canceledException.addSuppressed(t);
          responseCallback.onFailure(RealCall.this, canceledException);
        }
        throw t;
      } finally {
        //移除當(dāng)前AsyncCall
        client.dispatcher().finished(this);
      }
    }

我們觀察以上代碼大部分是異常處理的邏輯豹缀,而try中第一句即返回了Response對(duì)象伯复,因此,我們主要看getResponseWithInterceptorChain()中的邏輯邢笙。

  Response getResponseWithInterceptorChain() throws IOException {
    // 建立一個(gè)完整的攔截器堆棧
    List<Interceptor> interceptors = new ArrayList<>();
     //將創(chuàng)建okhttpclient時(shí)的攔截器添加到interceptors
    interceptors.addAll(client.interceptors());
    //重試攔截器啸如,負(fù)責(zé)處理失敗后的重試與重定向
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    //請(qǐng)求轉(zhuǎn)化攔截器(用戶請(qǐng)求轉(zhuǎn)為服務(wù)器請(qǐng)求,服務(wù)器響應(yīng)轉(zhuǎn)為用戶響應(yīng))
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //緩存攔截器氮惯。負(fù)責(zé)
    //1.根據(jù)條件叮雳,緩存配置,有效期等返回緩存響應(yīng)妇汗,也可增加到緩存帘不。
    //2.設(shè)置請(qǐng)求頭(If-None-Match、If-Modified-Since等) 服務(wù)器可能返回304(未修改)
    //3.可配置自定義的緩存攔截器杨箭。
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //網(wǎng)絡(luò)連接攔截器寞焙,主要負(fù)責(zé)和服務(wù)器建立連接。
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      //創(chuàng)建okhttpclient時(shí)設(shè)置的networkInterceptors
      interceptors.addAll(client.networkInterceptors());
    }
    //數(shù)據(jù)流攔截器告唆,主要負(fù)責(zé)像服務(wù)器發(fā)送和讀取數(shù)據(jù)棺弊,請(qǐng)求報(bào)文封裝和解析晶密。
    interceptors.add(new CallServerInterceptor(forWebSocket));
    //責(zé)任鏈模式的創(chuàng)建擒悬。
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
      //啟動(dòng)責(zé)任鏈
      Response response = chain.proceed(originalRequest);
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
    }
  }

其實(shí)上述邏輯中,主要干了3件事稻艰。

    1. 將所有攔截器添加到了list中
    1. 通過(guò)RealInterceptorChain創(chuàng)建責(zé)任鏈懂牧。
    1. 通過(guò)chain.proceed(originalRequest)啟動(dòng)執(zhí)行。

我們只要搞懂創(chuàng)建責(zé)任鏈的邏輯尊勿,以及啟動(dòng)責(zé)任鏈的邏輯就全都明白了僧凤,ok,我們看下具體代碼

//通過(guò)RealInterceptorChain構(gòu)造函數(shù)創(chuàng)建每一個(gè)責(zé)任對(duì)象
 public RealInterceptorChain(List<Interceptor> interceptors, Transmitter transmitter,
      @Nullable Exchange exchange, int index, Request request, Call call,
      int connectTimeout, int readTimeout, int writeTimeout) {
    this.interceptors = interceptors;
    this.transmitter = transmitter;
    this.exchange = exchange;
    this.index = index;
    this.request = request;
    this.call = call;
    this.connectTimeout = connectTimeout;
    this.readTimeout = readTimeout;
    this.writeTimeout = writeTimeout;
  }
//啟動(dòng)責(zé)任鏈代碼
 @Override 
 public Response proceed(Request request) throws IOException {
    return proceed(request, transmitter, exchange);
  }
//啟動(dòng)責(zé)任鏈代碼
  public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
      throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // 如果我們已經(jīng)有一個(gè)流元扔,請(qǐng)確認(rèn)傳入的請(qǐng)求將使用它躯保。
    if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // 如果我們已經(jīng)有一個(gè)流,確認(rèn)這是對(duì)鏈的唯一調(diào)用澎语。
    if (this.exchange != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // 調(diào)用鏈中的下一個(gè)攔截器途事,注意參數(shù)index+1,通過(guò)+1的方式循環(huán)interceptors list中的攔截器
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    //執(zhí)行當(dāng)前攔截器邏輯擅羞,并設(shè)置下一個(gè)攔截器對(duì)象尸变。
    Response response = interceptor.intercept(next);

    // 確認(rèn)下一個(gè)攔截器對(duì)chain.proceed()進(jìn)行了所需的調(diào)用。
    if (exchange != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }

雖然看著上述這段代碼很長(zhǎng)减俏,但是大篇幅都在判斷各種異常情況召烂,實(shí)際做的事非常簡(jiǎn)單。
1.創(chuàng)建完RealInterceptorChain后娃承,通過(guò)procee()判斷各種異常奏夫,并獲取當(dāng)前Interceptor對(duì)象怕篷。
2.通過(guò)Interceptor.intercept(RealInterceptorChain)啟動(dòng)當(dāng)前攔截器邏輯,并且觸發(fā)下一個(gè)攔截器啟動(dòng)酗昼。
3.如果當(dāng)前攔截器出現(xiàn)異常等錯(cuò)誤匙头,則終止責(zé)任鏈。

具體的情況我們還需要看一個(gè)攔截器內(nèi)部的邏輯仔雷,我們以簡(jiǎn)單的ConnectInterceptor為例蹂析。

public final class ConnectInterceptor implements Interceptor {
  public final OkHttpClient client;

  public ConnectInterceptor(OkHttpClient client) {
    this.client = client;
  }

  @Override public Response intercept(Chain chain) throws IOException {
    //chain實(shí)際上是下一個(gè)責(zé)任對(duì)象。
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    Transmitter transmitter = realChain.transmitter();

    // 我們需要網(wǎng)絡(luò)來(lái)滿足這個(gè)要求碟婆〉绺В可能用于驗(yàn)證條件GET。
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);
    //執(zhí)行下一個(gè)攔截器責(zé)任對(duì)象的proceed方法竖共。
    return realChain.proceed(request, transmitter, exchange);
  }
}

可見(jiàn)蝙叛,Interceptor.intercept(Chain chain)接收的是下一個(gè)攔截器責(zé)任對(duì)象。
該方法中執(zhí)行了自己攔截器該有的邏輯公给,如果沒(méi)異常則直接通過(guò)下一個(gè)攔截器責(zé)任對(duì)象的proceed()啟動(dòng)了下一個(gè)攔截器邏輯借帘。
ok我們?cè)诨仡^看下,AsyncCall.execute()中的finally中的那句代碼 client.dispatcher().finished(this);

//Dispatcher.finished()
 void finished(AsyncCall call) {
    call.callsPerHost().decrementAndGet();
    finished(runningAsyncCalls, call);
  }

  private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
      //移除隊(duì)列淌铐,如果失敗則拋異常
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      idleCallback = this.idleCallback;
    }
    //這個(gè)方法是不是有點(diǎn)眼熟肺然,主要用來(lái)將readyAsyncCalls符合條件的添加到runningAsyncCalls中,并運(yùn)行腿准。
    boolean isRunning = promoteAndExecute();
     //閑置調(diào)用
    if (!isRunning && idleCallback != null) {
      idleCallback.run();
    }
  }

ok至此所有的流程都非常清楚了际起。至于請(qǐng)求細(xì)節(jié)需要具體到了每一個(gè)攔截器里。我打算單獨(dú)開(kāi)一篇來(lái)分析吐葱。
看到此處街望,如果對(duì)你有一點(diǎn)幫助,麻煩給個(gè)贊鼓勵(lì)一下弟跑。

其實(shí)寫(xiě)博客是一個(gè)自驅(qū)的學(xué)習(xí)管理方式灾前。能給小伙伴說(shuō)明白的,那你必定早已心中有數(shù)孟辑。翻閱偉大的框架代碼就好比面對(duì)面跟這個(gè)偉人學(xué)習(xí)哎甲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市扑浸,隨后出現(xiàn)的幾起案子烧给,更是在濱河造成了極大的恐慌,老刑警劉巖喝噪,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件础嫡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)榴鼎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)伯诬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人巫财,你說(shuō)我怎么就攤上這事盗似。” “怎么了平项?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵赫舒,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我闽瓢,道長(zhǎng)接癌,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任扣讼,我火速辦了婚禮缺猛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘椭符。我一直安慰自己荔燎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布销钝。 她就那樣靜靜地躺著有咨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪曙搬。 梳的紋絲不亂的頭發(fā)上摔吏,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音纵装,去河邊找鬼。 笑死据某,一個(gè)胖子當(dāng)著我的面吹牛橡娄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播癣籽,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼挽唉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了筷狼?” 一聲冷哼從身側(cè)響起瓶籽,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎埂材,沒(méi)想到半個(gè)月后塑顺,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年严拒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扬绪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡裤唠,死狀恐怖挤牛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情种蘸,我是刑警寧澤墓赴,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站航瞭,受9級(jí)特大地震影響竣蹦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沧奴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一痘括、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧滔吠,春花似錦纲菌、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至冬骚,卻和暖如春椅贱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背只冻。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工庇麦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喜德。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓山橄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親舍悯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子航棱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345