Volley使用總結(jié)及源碼分析(二)

前提

上一次講了Volley的核心RequestQueue,如果沒(méi)有看過(guò)的話請(qǐng)參看Volley使用總結(jié)及源碼分析(一)楚昭,在其start方法中如庭,維護(hù)了五個(gè)線程,一個(gè)緩存線程和四個(gè)網(wǎng)絡(luò)線程舒岸,下面我們繼續(xù)分析绅作,在上一次提到注意線程初始化的時(shí)候傳入的參數(shù),那參數(shù)傳入之后到底做了什么操作蛾派?

緩存線程

public class CacheDispatcher extends Thread {
    private static final boolean DEBUG = VolleyLog.DEBUG;
    private final BlockingQueue<Request<?>> mCacheQueue;
    private final BlockingQueue<Request<?>> mNetworkQueue;
    private final Cache mCache;
    private final ResponseDelivery mDelivery;
    private volatile boolean mQuit = false;
    public CacheDispatcher(
            BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue,
            Cache cache, ResponseDelivery delivery) {
        //緩存請(qǐng)求隊(duì)列
        mCacheQueue = cacheQueue;
        //網(wǎng)絡(luò)請(qǐng)求隊(duì)列
        mNetworkQueue = networkQueue;
        //DiskBasedCache類(lèi)具體對(duì)象俄认,用于本地緩存
        mCache = cache;
        //將響應(yīng)傳遞回主線程
        mDelivery = delivery;
    }
    //退出線程
    public void quit() {
        mQuit = true;
        interrupt();
    }
    @Override
    public void run() {
        if (DEBUG) VolleyLog.v("start new dispatcher");      Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        //初始化緩存
        mCache.initialize();
        while (true) {
            try {
                final Request<?> request = mCacheQueue.take();
                request.addMarker("cache-queue-take");
                //判斷是否取消
                if (request.isCanceled()) {
                    request.finish("cache-discard-canceled");
                    continue;
                }
                //當(dāng)前請(qǐng)求是否有緩存个少,
                Cache.Entry entry = mCache.get(request.getCacheKey());
                if (entry == null) {
                    request.addMarker("cache-miss");
                    //沒(méi)有緩存,加入到網(wǎng)絡(luò)請(qǐng)求隊(duì)列
                    mNetworkQueue.put(request);
                    continue;
                }
                //判斷緩存是否過(guò)期
                if (entry.isExpired()) {
                    request.addMarker("cache-hit-expired");
                    request.setCacheEntry(entry);
                    //過(guò)期的話重新加入網(wǎng)絡(luò)請(qǐng)求隊(duì)列
                    mNetworkQueue.put(request);
                    continue;
                }
                //緩存沒(méi)有過(guò)期的話眯杏,解析緩存為請(qǐng)求的響應(yīng)
                request.addMarker("cache-hit");
                Response<?> response = request.parseNetworkResponse(
                        new NetworkResponse(entry.data, entry.responseHeaders));
                request.addMarker("cache-hit-parsed");
                //原始數(shù)據(jù)源是否需要刷新
                if (!entry.refreshNeeded()) {
                 //將解析后的響應(yīng)使用Delivery分發(fā)
                  mDelivery.postResponse(request, response);
                } else {
                  //重新請(qǐng)求網(wǎng)絡(luò)夜焦,刷新緩存
                  request.addMarker("cache-hit-refresh-needed");
                    request.setCacheEntry(entry);
                    response.intermediate = true;
                    mDelivery.postResponse(request, response, new Runnable() {
                        @Override
                        public void run() {
                            try {
                                mNetworkQueue.put(request);
                            } catch (InterruptedException e) {
                                // Not much we can do about this.
                            }
                        }
                    });
                }
            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                if (mQuit) {
                    return;
                }
                continue;
            }
        }
    }
}

?代碼中加了中文注釋?zhuān)梢钥吹?code>CacheDispatcher繼承了Thread,實(shí)現(xiàn)了run方法岂贩。構(gòu)造方法將傳入的四個(gè)參數(shù)保存在成員變量中茫经,quit方法設(shè)置取消標(biāo)志,中斷線程萎津。run方法中首先對(duì)mCache進(jìn)行初始化卸伞,然后不斷從緩存請(qǐng)求隊(duì)列中取請(qǐng)求處理mCacheQueue.take();,隊(duì)列為空則等待姜性,請(qǐng)求處理結(jié)束則將結(jié)果傳遞給ResponseDelivery 去執(zhí)行后續(xù)處理瞪慧。當(dāng)結(jié)果未緩存過(guò)、緩存失效或緩存需要刷新的情況下部念,該請(qǐng)求都需要重新進(jìn)入NetworkDispatcher去調(diào)度處理弃酌。

網(wǎng)絡(luò)線程

public class NetworkDispatcher extends Thread {
    private final BlockingQueue<Request<?>> mQueue;
    private final Network mNetwork;
    private final Cache mCache;
    private final ResponseDelivery mDelivery;
    private volatile boolean mQuit = false;
    public NetworkDispatcher(BlockingQueue<Request<?>> queue,
            Network network, Cache cache,
            ResponseDelivery delivery) {
        //網(wǎng)絡(luò)請(qǐng)求隊(duì)列
        mQueue = queue;
        //具體執(zhí)行網(wǎng)絡(luò)交互
        mNetwork = network;
        //DiskBasedCache類(lèi)具體對(duì)象,用于本地緩存
        mCache = cache;
         //將響應(yīng)傳遞回主線程
        mDelivery = delivery;
    }
    public void quit() {
        mQuit = true;
        interrupt();
    }
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private void addTrafficStatsTag(Request<?> request) {
        // Tag the request (if API >= 14)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
           TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
        }
    }
    @Override
    public void run() {
        //設(shè)置線程優(yōu)先級(jí)
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        while (true) {
            //記錄開(kāi)始時(shí)間
            long startTimeMs = SystemClock.elapsedRealtime();
            Request<?> request;
            try {
                //從隊(duì)列中取出網(wǎng)絡(luò)請(qǐng)求
                request = mQueue.take();
            } catch (InterruptedException e) {
                if (mQuit) {
                    return;
                }
                continue;
            }
            try {
                request.addMarker("network-queue-take");
                //判斷是否取消
                if (request.isCanceled()) {
                    request.finish("network-discard-cancelled");
                    continue;
                }
                addTrafficStatsTag(request);
                //performRequest中儡炼,調(diào)用HttpStack處理請(qǐng)求
                NetworkResponse networkResponse = mNetwork.performRequest(request);
                request.addMarker("network-http-complete");
                if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                    request.finish("not-modified");
                    continue;
                }
                //使用request的parseNetworkResponse方法解析妓湘,請(qǐng)求的網(wǎng)絡(luò)響應(yīng)
                Response<?> response = request.parseNetworkResponse(networkResponse);
                request.addMarker("network-parse-complete");
                if (request.shouldCache() && response.cacheEntry != null) {
                    //添加緩存
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                    request.addMarker("network-cache-written");
                }
                request.markDelivered();
                //將解析后的響應(yīng)使用Delivery分發(fā)
                mDelivery.postResponse(request, response);
            } catch (VolleyError volleyError) {volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                parseAndDeliverNetworkError(request, volleyError);
            } catch (Exception e) {
                VolleyLog.e(e, "Unhandled exception %s", e.toString());
                VolleyError volleyError = new VolleyError(e);
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                mDelivery.postError(request, volleyError);
            }
        }
    }
    private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
        error = request.parseNetworkError(error);
        mDelivery.postError(request, error);
    }
}

?可以看到NetworkDispatcherCacheDispatcher很像,主要是run方法中的流程不同乌询。設(shè)置線程優(yōu)先級(jí)榜贴,不斷從網(wǎng)絡(luò)請(qǐng)求隊(duì)列中取出網(wǎng)絡(luò)請(qǐng)求,調(diào)用BasicNetwork中的performRequest方法處理請(qǐng)求妹田,在該方法中調(diào)用HttpStack處理請(qǐng)求唬党,并將結(jié)果轉(zhuǎn)換為可被ResponseDelivery處理的NetworkResponse。使用request.parseNetworkResponse處理網(wǎng)絡(luò)返回的響應(yīng)鬼佣,加入緩存驶拱,返回處理后的響應(yīng)結(jié)果。

總結(jié)

?默認(rèn)情況下晶衷,所有請(qǐng)求都會(huì)經(jīng)過(guò)緩存線程判斷蓝纲,如果存在緩存且沒(méi)有過(guò)期,則直接返回緩存的響應(yīng)晌纫,否則加入網(wǎng)絡(luò)線程中税迷,在網(wǎng)絡(luò)線程中,會(huì)調(diào)用HttpStack處理請(qǐng)求锹漱,返回的響應(yīng)使用request的parseNetworkResponse方法進(jìn)一步進(jìn)行解析箭养,并將結(jié)果緩存到本地。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凌蔬,一起剝皮案震驚了整個(gè)濱河市露懒,隨后出現(xiàn)的幾起案子闯冷,更是在濱河造成了極大的恐慌,老刑警劉巖懈词,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛇耀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡坎弯,警方通過(guò)查閱死者的電腦和手機(jī)纺涤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)抠忘,“玉大人撩炊,你說(shuō)我怎么就攤上這事∑槁觯” “怎么了拧咳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)囚灼。 經(jīng)常有香客問(wèn)我骆膝,道長(zhǎng),這世上最難降的妖魔是什么灶体? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任阅签,我火速辦了婚禮,結(jié)果婚禮上蝎抽,老公的妹妹穿的比我還像新娘政钟。我一直安慰自己,他們只是感情好樟结,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布养交。 她就那樣靜靜地躺著,像睡著了一般瓢宦。 火紅的嫁衣襯著肌膚如雪层坠。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天刁笙,我揣著相機(jī)與錄音,去河邊找鬼谦趣。 笑死疲吸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的前鹅。 我是一名探鬼主播摘悴,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼舰绘!你這毒婦竟也來(lái)了蹂喻?” 一聲冷哼從身側(cè)響起葱椭,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎口四,沒(méi)想到半個(gè)月后孵运,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蔓彩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年治笨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赤嚼。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旷赖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出更卒,到底是詐尸還是另有隱情等孵,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布蹂空,位于F島的核電站俯萌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏腌闯。R本人自食惡果不足惜绳瘟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望姿骏。 院中可真熱鬧糖声,春花似錦、人聲如沸分瘦。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嘲玫。三九已至悦施,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間去团,已是汗流浹背抡诞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留土陪,地道東北人昼汗。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鬼雀,于是被迫代替她去往敵國(guó)和親顷窒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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