Android-OKHTTP底層原理淺析(一)

如果直到今天還有人跟你說(shuō)茉帅,不要用那些什么開(kāi)源框架,比如okhttp锭弊,不好堪澎,我們要自己寫(xiě)!
你可以反手就是一巴掌給他味滞,因?yàn)閛khttp在很久之前已經(jīng)被谷歌收錄樱蛤,谷歌已經(jīng)參照這個(gè)庫(kù)的寫(xiě)法修改了對(duì)應(yīng)的底層封裝,雖然咱們依然用的是httpurlconnection剑鞍,但其實(shí)內(nèi)部實(shí)現(xiàn)已經(jīng)被修改過(guò)了昨凡。所以簡(jiǎn)單來(lái)講,okhttp就等于源碼蚁署,下次再有人說(shuō)這種不負(fù)責(zé)的話你就往死里打便脊!
好了,我們回到正題光戈,okhttp是一個(gè)什么鬼東西我就不具體說(shuō)了哪痰,我打算把底層略淺的過(guò)一遍,一來(lái)增加自己的印象久妆,二來(lái)各位看官也可以給自己過(guò)一遍印象晌杰,我覺(jué)得看源碼就應(yīng)該只抓重點(diǎn),不然你會(huì)迷失在這片海洋里筷弦,人家一個(gè)團(tuán)隊(duì)辛辛苦苦寫(xiě)了那么久的東西肋演,你一個(gè)人怎么可能那么快能夠全盤(pán)掌握呢對(duì)吧。
估計(jì)一篇文章是不夠分析的,所以我打算分為兩篇或三篇來(lái)解析爹殊,那么話不多說(shuō)蜕乡,開(kāi)始我們的第一篇。
首先我們上個(gè)使用方式梗夸,然后我們從使用方式開(kāi)始入手一步步了解异希。

OkHttpClient okHttpClient = new OkHttpClient();
        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) {
                
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });

首先,enqueue是異步調(diào)用的方式绒瘦,同步調(diào)用是用execute称簿,他們的底層就前面有一些不一樣,后面都一樣惰帽,所以直接講異步的就行憨降。那我們先看看newCall,點(diǎn)進(jìn)去(其實(shí)不看都可以猜到他是new一個(gè)call啦~)

@Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }
繼續(xù)跳
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

對(duì)吧该酗,返回了一個(gè)RealCall實(shí)例授药,保存了一些參數(shù),那么回到外面呜魄,我們看看call.enqueue()

void enqueue(Callback responseCallback);

咦悔叽,沒(méi)看到實(shí)現(xiàn),因?yàn)镽ealCall才是Call的實(shí)現(xiàn)類爵嗅,那咱們應(yīng)該去那邊看娇澎,過(guò)去查一下

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

誒,找到了睹晒。來(lái)趟庄,開(kāi)始一步步深入了,這里我們先去看看client.dispatcher()

public Dispatcher dispatcher() {
    return dispatcher;
  }
下面是這個(gè)類的開(kāi)頭伪很,有一個(gè)線索點(diǎn)
public final class Dispatcher {
  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;
  private Runnable idleCallback;

  /** Executes calls. Created lazily. */
  private ExecutorService executorService;
...

看到ExecutorService了戚啥,其實(shí)Dispatcher就是一個(gè)線程分發(fā)器,用來(lái)處理請(qǐng)求線程的锉试,利用線程池類去維護(hù)猫十。那我們繼續(xù),回到上面去看看dispatcher().enqueue()

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

首先把自己添加進(jìn)了隊(duì)列呆盖,然后調(diào)用了線程池的execute方法拖云,ok完成它的使命了,那咱們繼續(xù)回到前面絮短,看看最后的enqueue(new AsyncCall(responseCallback))的AsyncCall是個(gè)什么鬼

final class AsyncCall extends NamedRunnable {

窩江兢,是個(gè)線程(這TM不是廢話嗎!)丁频,那我們來(lái)找找它的Run方法,咦,沒(méi)有席里,那就去父類看看

public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

在這里了叔磷,調(diào)用了execute()方法,然而是個(gè)抽象方法奖磁,那就去他子類找這個(gè)方法的實(shí)現(xiàn)

@Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        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 {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }

兄弟們改基,execute()這個(gè)方法名是不是有點(diǎn)熟悉?
對(duì)的咖为,如果我們一開(kāi)始用同步秕狰,那么會(huì)直接跑到這里來(lái)。
所以說(shuō)這兩個(gè)方法后面從這里開(kāi)始都是一樣的了躁染,前面就是上面講的那些不一樣鸣哀,多了個(gè)線程池。
好吞彤,接下來(lái)要深入的是getResponseWithInterceptorChain我衬,走起

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 (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

要開(kāi)始繼續(xù)深入了,可以這樣講饰恕,okhttp的核心之一就是這一堆的攔截器挠羔。但是咱們先剎個(gè)車,先來(lái)回顧一下剛剛走的流程:

1埋嵌,我們使用okHttpClient.newCall實(shí)例出了Call的實(shí)現(xiàn)類
2破加,我們調(diào)用了它的異步方法 ,里面重點(diǎn)是client.dispatcher().enqueue(new AsyncCall(responseCallback))
3雹嗦,其中Dispatcher是這里面的分發(fā)器拌喉,它內(nèi)部使用了ExecutorService線程池,然后將我們的AsyncCall添加了進(jìn)去
4俐银,我們的AsyncCall實(shí)現(xiàn)了Runnable尿背,在run方法里執(zhí)行了execute(),這也是一開(kāi)始調(diào)用同步方法后走的地方
5捶惜,execute()方法注冊(cè)了一系列攔截器田藐,并組成了責(zé)任鏈(劃重點(diǎn),責(zé)任鏈設(shè)計(jì)模式吱七,Okhttp的核心)

ok汽久,這一篇先到這過(guò),下一篇咱們從責(zé)任鏈這里開(kāi)始踊餐。
Android-OKHttp底層原理淺析(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末景醇,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吝岭,更是在濱河造成了極大的恐慌三痰,老刑警劉巖吧寺,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異散劫,居然都是意外死亡稚机,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)获搏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)赖条,“玉大人,你說(shuō)我怎么就攤上這事常熙∥痴В” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵裸卫,是天一觀的道長(zhǎng)仿贬。 經(jīng)常有香客問(wèn)我,道長(zhǎng)彼城,這世上最難降的妖魔是什么诅蝶? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮募壕,結(jié)果婚禮上调炬,老公的妹妹穿的比我還像新娘。我一直安慰自己舱馅,他們只是感情好缰泡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著代嗤,像睡著了一般棘钞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上干毅,一...
    開(kāi)封第一講書(shū)人閱讀 51,198評(píng)論 1 299
  • 那天宜猜,我揣著相機(jī)與錄音,去河邊找鬼硝逢。 笑死姨拥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的渠鸽。 我是一名探鬼主播叫乌,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼徽缚!你這毒婦竟也來(lái)了憨奸?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤凿试,失蹤者是張志新(化名)和其女友劉穎排宰,沒(méi)想到半個(gè)月后似芝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡额各,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年国觉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吧恃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虾啦。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖痕寓,靈堂內(nèi)的尸體忽然破棺而出傲醉,到底是詐尸還是另有隱情,我是刑警寧澤呻率,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布硬毕,位于F島的核電站,受9級(jí)特大地震影響礼仗,放射性物質(zhì)發(fā)生泄漏吐咳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一元践、第九天 我趴在偏房一處隱蔽的房頂上張望韭脊。 院中可真熱鬧,春花似錦单旁、人聲如沸沪羔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蔫饰。三九已至,卻和暖如春愉豺,著一層夾襖步出監(jiān)牢的瞬間篓吁,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工蚪拦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杖剪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓外盯,卻偏偏與公主長(zhǎng)得像摘盆,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饱苟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容