Android Volley 源碼總結(jié)

主要參考: http://blog.csdn.net/guolin_blog/article/details/17656437
工作流程圖:

volley_architecture.png

"
其中藍(lán)色部分代表主線程唆阿,綠色部分代表緩存線程弦撩,橙色部分代表網(wǎng)絡(luò)線程咽袜。我們在主線程中調(diào)用RequestQueue的add()方法來添加一條網(wǎng)絡(luò)請求,這條請求會先被加入到緩存隊列當(dāng)中歇由,如果發(fā)現(xiàn)可以找到相應(yīng)的緩存結(jié)果就直接讀取緩存并解析井联,然后回調(diào)給主線程疑枯。如果在緩存中沒有找到結(jié)果切省,則將這條請求加入到網(wǎng)絡(luò)請求隊列中最岗,然后處理發(fā)送HTTP請求,解析響應(yīng)結(jié)果朝捆,寫入緩存般渡,并回調(diào)主線程。
"

這里總結(jié)幾個技術(shù)要點:

Gingerbread之前芙盘, 底層網(wǎng)絡(luò)請求的實現(xiàn)使用HttpClient, Gingerbread之后驯用, 底層實現(xiàn)就開始使用HttpUrlConnection了, 因為Gingerbread之前的HttpUrlConnection不穩(wěn)定.

//Volley.java
    public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
        //File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
        File cacheDir = new File(FeatureConfig.ROOT_CACHE_PATH_BASE, DEFAULT_CACHE_DIR);

        String userAgent = "volley/0";
        try {
            String packageName = context.getPackageName();
            PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
            userAgent = packageName + "/" + info.versionCode;
        } catch (Throwable e) {
        }

        if (stack == null) {
            if (Build.VERSION.SDK_INT >= 9) {
                //use httpUrlConnection
                stack = new HurlStack();
            } else {
                // Prior to Gingerbread, HttpUrlConnection was unreliable.
                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
            }
        }

        Network network = new BasicNetwork(stack);

        RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
        queue.start();

        return queue;
    }

RequestQueue.java
    public void start() {
        stop();  // Make sure any currently running dispatchers are stopped.
        // Create the cache dispatcher and start it.
        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
        mCacheDispatcher.start();
//這里啟動一個Cache線程儒老, 不斷的從RequestQueue隊列里取元素.
        // Create network dispatchers (and corresponding threads) up to the pool size.
//默認(rèn)創(chuàng)建4個Network線程蝴乔, 不斷的在自己的隊列里取元素, 執(zhí)行真正的網(wǎng)絡(luò)請求.
        for (int i = 0; i < mDispatchers.length; i++) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }
    }

CacheDispatcher是一個Thread, 它的run()方法驮樊, 是個死循環(huán).

public class CacheDispatcher extends Thread {

    @Override
    public void run() {
        if (DEBUG) VolleyLog.v("start new dispatcher");
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

        // Make a blocking call to initialize the cache.
        mCache.initialize();

        while (true) {
            try {
                // Get a request from the cache triage queue, blocking until
                // at least one is available.
        // 阻塞在這個, 從隊列里取元素.
                final Request<?> request = mCacheQueue.take();
                request.addMarker("cache-queue-take");

                // If the request has been canceled, don't bother dispatching it.
                if (request.isCanceled()) {
                    request.finish("cache-discard-canceled");
                    continue;
                }

                // Attempt to retrieve this item from cache.
                Cache.Entry entry = mCache.get(request.getCacheKey());
                if (entry == null) {
                    request.addMarker("cache-miss");
                    // Cache miss; send off to the network dispatcher.
                    mNetworkQueue.put(request);
                    continue;
                }
...

                // We have a cache hit; parse its data for delivery back to the request.
                request.addMarker("cache-hit");
                Response<?> response = null;
                try {
                    response = request.parseNetworkResponse(
                            new NetworkResponse(entry.data, entry.responseHeaders));
                } catch (Exception e) {
                    mDelivery.postError(request, new ParseError(e));
                    continue;
                } catch (Error error) {
                    mDelivery.postError(request, new ParseError(error));
                    continue;
                }
                request.addMarker("cache-hit-parsed");

                if (!entry.refreshNeeded()) {
                    // Completely unexpired cache hit. Just deliver the response.
                    mDelivery.postResponse(request, response);
                } else {
                    // Soft-expired cache hit. We can deliver the cached response,
                    // but we need to also send the request to the network for
                    // refreshing.
                    request.addMarker("cache-hit-refresh-needed");
                    request.setCacheEntry(entry);

                    // Mark the response as intermediate.
                    response.intermediate = true;

                    // Post the intermediate response back to the user and have
                    // the delivery then forward the request along to the network.
                    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;
            } catch (OutOfMemoryError error) {
                if (mQuit) {
                    return;
                }
                continue;
            }
        }
    }

NetworkDispatcher也是一個Thread, 它的run()方法薇正, 是個死循環(huán).

public class NetworkDispatcher extends Thread {
public void run() {
    while(true) {
        request = mQueue.take(); //阻塞在這里
        NetworkResponse networkResponse = mNetwork.performRequest(request);

        Response<?> response = request.parseNetworkResponse(networkResponse);

                if (request.shouldCache() && response.cacheEntry != null) {
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                    request.addMarker("network-cache-written");
                }
    }   
}
Volley的總體框架還是非常的清晰的.

========DONE=========

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市囚衔,隨后出現(xiàn)的幾起案子挖腰,更是在濱河造成了極大的恐慌,老刑警劉巖佳魔,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件曙聂,死亡現(xiàn)場離奇詭異,居然都是意外死亡鞠鲜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門断国,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贤姆,“玉大人,你說我怎么就攤上這事稳衬∠技瘢” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵薄疚,是天一觀的道長碧信。 經(jīng)常有香客問我,道長街夭,這世上最難降的妖魔是什么砰碴? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮板丽,結(jié)果婚禮上呈枉,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好猖辫,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布酥泞。 她就那樣靜靜地躺著,像睡著了一般啃憎。 火紅的嫁衣襯著肌膚如雪芝囤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天辛萍,我揣著相機(jī)與錄音悯姊,去河邊找鬼。 笑死叹阔,一個胖子當(dāng)著我的面吹牛挠轴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播耳幢,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼岸晦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了睛藻?” 一聲冷哼從身側(cè)響起启上,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎店印,沒想到半個月后冈在,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡按摘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年包券,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炫贤。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡溅固,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出兰珍,到底是詐尸還是另有隱情侍郭,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布掠河,位于F島的核電站亮元,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏唠摹。R本人自食惡果不足惜爆捞,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望跃闹。 院中可真熱鬧嵌削,春花似錦毛好、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至艇劫,卻和暖如春吼驶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背店煞。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工蟹演, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人顷蟀。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓酒请,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鸣个。 傳聞我的和親對象是個殘疾皇子羞反,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

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