OKHttp

定義:Okhttp是對Socket的封裝。有三個(gè)主要的類喳挑,Request彬伦,Response,Call
默認(rèn)使用new OkHttpClient() 創(chuàng)建初client對象伊诵。
如果需要初始化網(wǎng)絡(luò)請求的參數(shù)单绑,如timeout,interceptor等,可以創(chuàng)建Builder曹宴,通過builder.build() 創(chuàng)建初client對象搂橙。

三個(gè)問題

1.請求發(fā)送到什么哪去了?框架里放到哪里了笛坦?
請求通過execute方法發(fā)送到框架中的兩個(gè)隊(duì)列中去了:運(yùn)行中的隊(duì)列区转;等待中的隊(duì)列,如果說運(yùn)行中的隊(duì)列總數(shù)小于64并且訪問同一目標(biāo)機(jī)器請求小于5版扩,就進(jìn)入運(yùn)行隊(duì)列废离,否則進(jìn)入等待隊(duì)列

2.請求被誰處理:請求提交到運(yùn)行中隊(duì)列后,交給線程池來處理礁芦,直接處理請求

3.請求是怎么被維護(hù)的:每次請求完成后蜻韭,client.dispath調(diào)用finished方法,對運(yùn)行中的隊(duì)列和等待中的隊(duì)列進(jìn)行數(shù)據(jù)處理柿扣,(在符合條件的情況下肖方,將等待中的加入到運(yùn)行中隊(duì)列中去)

流程

1.通過
生成一個(gè)OkHttpClient client = new OkHttpClient();

2.構(gòu)建一個(gè)Request requet = new Request.Builder()
.get().url("https:www.baidu.com").build();
3.通過client.newCall(request)得到Call,這個(gè)call是他的子類RealCall

4.通過call.execute(同步) 或call.enqueue(異步)啟動(dòng)

A:執(zhí)行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.先判斷這個(gè)call是否被執(zhí)行了,每個(gè)call只能被執(zhí)行一次未状,如果要一個(gè)完成一樣的call可以利用call的clone方法進(jìn)行克隆

2.利用client.dispathcer().execute(this)來進(jìn)行執(zhí)行,其中dispatcher.execute方法為

 synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

這里我剛開始沒有相同窥妇,之后他加入隊(duì)列后怎么調(diào)用的,后來發(fā)現(xiàn)在 下一個(gè)方法調(diào)用的
3.調(diào)用getResponseWithInterceptorChain函數(shù)來獲取HTTP返回的結(jié)果,這里的originalRequest就是我們的請求剛剛加入隊(duì)列的是RealCall娩践,通過chain.proceed(originalRequest)去調(diào)用

 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自己已經(jīng)執(zhí)行完畢
client.dispatcher().finished(this);
會(huì)執(zhí)行finished(隊(duì)列活翩、call,true)
其中這個(gè)方法是同步和異步都調(diào)用的方法,通過第三個(gè)參數(shù)翻伺,是否執(zhí)行promoteCall方法具體的執(zhí)行會(huì)不同材泄,promoteCall方法

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
        int runningCallsCount;
        Runnable idleCallback;
        synchronized (this) {
            //TODO calls 移除隊(duì)列
            if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
            //TODO 檢查是否為異步請求,檢查等候的隊(duì)列 readyAsyncCalls吨岭,如果存在等候隊(duì)列拉宗,則將等候隊(duì)列加入執(zhí)行隊(duì)列
            if (promoteCalls) promoteCalls();
            //TODO 運(yùn)行隊(duì)列的數(shù)量
            runningCallsCount = runningCallsCount();
            idleCallback = this.idleCallback;
        }
        //閑置調(diào)用
        if (runningCallsCount == 0 && idleCallback != null) {
            idleCallback.run();
        }
    }
    
    private void promoteCalls() {
        //TODO 檢查 運(yùn)行隊(duì)列 與 等待隊(duì)列
        if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
        if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

        //TODO 將等待隊(duì)列加入到運(yùn)行隊(duì)列中
        for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
            AsyncCall call = i.next();
            //TODO  相同host的請求沒有達(dá)到最大,加入運(yùn)行隊(duì)列
            if (runningCallsForHost(call) < maxRequestsPerHost) {
                i.remove();
                runningAsyncCalls.add(call);
                executorService().execute(call);
            }

            if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
        }
    }

B執(zhí)行Enqueue

// RealCall.java
@Override public void enqueue(Callback responseCallback) {
    synchronized (this) { // 如果這個(gè) call 已經(jīng)被執(zhí)行過,拋異常
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

 //TODO 執(zhí)行異步請求
    synchronized void enqueue(AsyncCall call) {
        //TODO 同時(shí)請求不能超過并發(fā)數(shù)(64,可配置調(diào)度器調(diào)整)
        //TODO okhttp會(huì)使用共享主機(jī)即 地址相同的會(huì)共享socket
        //TODO 同一個(gè)host最多允許5條線程通知執(zhí)行請求
        if (runningAsyncCalls.size() < maxRequests &&
                runningCallsForHost(call) < maxRequestsPerHost) {
            //TODO 加入運(yùn)行隊(duì)列 并交給線程池執(zhí)行
            runningAsyncCalls.add(call);
            //TODO AsyncCall 是一個(gè)runnable旦事,放到線程池中去執(zhí)行魁巩,查看其execute實(shí)現(xiàn)
            executorService().execute(call);
        } else {
            //TODO 加入等候隊(duì)列
            readyAsyncCalls.add(call);
        }
    }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市姐浮,隨后出現(xiàn)的幾起案子谷遂,更是在濱河造成了極大的恐慌,老刑警劉巖卖鲤,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肾扰,死亡現(xiàn)場離奇詭異,居然都是意外死亡蛋逾,警方通過查閱死者的電腦和手機(jī)集晚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來区匣,“玉大人偷拔,你說我怎么就攤上這事】鞴常” “怎么了条摸?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長铸屉。 經(jīng)常有香客問我钉蒲,道長,這世上最難降的妖魔是什么彻坛? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任顷啼,我火速辦了婚禮,結(jié)果婚禮上昌屉,老公的妹妹穿的比我還像新娘钙蒙。我一直安慰自己,他們只是感情好间驮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布躬厌。 她就那樣靜靜地躺著,像睡著了一般竞帽。 火紅的嫁衣襯著肌膚如雪扛施。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天屹篓,我揣著相機(jī)與錄音疙渣,去河邊找鬼。 笑死堆巧,一個(gè)胖子當(dāng)著我的面吹牛妄荔,可吹牛的內(nèi)容都是我干的泼菌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼啦租,長吁一口氣:“原來是場噩夢啊……” “哼哗伯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起篷角,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對情侶失蹤焊刹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后内地,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赋除,尸身上長有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
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望障贸。 院中可真熱鬧错森,春花似錦、人聲如沸篮洁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袁波。三九已至瓦阐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間篷牌,已是汗流浹背垄分。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留娃磺,地道東北人薄湿。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親豺瘤。 傳聞我的和親對象是個(gè)殘疾皇子吆倦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

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