Vollery原始碼閱讀(二)

disable發表於2021-09-09

上節寫到關於 Vollery 的前半部分,需要檢視的點選 , 這次主要檢視當我們真正 add request 的時候做進一步檢視。

我們還是從使用的方法作為我們的切入點:

mQueue.add(postRequest);//當我們向佇列中新增一個網路請求

跟進,檢視 RequestQueue#add() 方法:

/**
     * Staging area for requests that already have a duplicate request in
     * flight.
     * 儲存有重複請求的request暫存區,我個人認為就是如果 正在處理A發出的一個請求,此時又來一個A發出同樣的一個請求,那麼第二個請求就會暫時儲存在這個集合中
     */private final Map<String, Queue<Request<?>>> mWaitingRequests = new HashMap<String, Queue<Request<?>>>();public <T> Request<T> add(Request<T> request) {        // Tag the request as belonging to this queue and add it to the set of
        // current requests.
        request.setRequestQueue(this);        synchronized (mCurrentRequests) {
            mCurrentRequests.add(request);
        }        // Process requests in the order they are added.
        //按照新增請求的順序處理請求
        request.setSequence(getSequenceNumber());
        request.addMarker("add-to-queue");        // If the request is uncacheable, skip the cache queue and go straight
        // to the network.
        //判斷是否可以快取了,不快取就新增到網路請求佇列中去return,前面已經說過這個 mNetworkQueue 儲存管理網路請求佇列的
        //預設是可以快取的,在Request的構造方法可以看到
         //public Request(int method, String url, ErrorListener listener) {
            // this.mShouldCache = true;
        // }
        if (!request.shouldCache()) {
            mNetworkQueue.add(request);            return request;
        }        
        //直接到下面
        // Insert request into stage if there's already a request with the same
        // cache key in flight.
        synchronized (mWaitingRequests) {            //首先檢視是否快取過,取key
            String cacheKey = request.getCacheKey();            //如果快取過
            if (mWaitingRequests.containsKey(cacheKey)) {                // There is already a request in flight. Queue up.
                Queue<Request<?>> stagedRequests = mWaitingRequests
                        .get(cacheKey);                if (stagedRequests == null) {
                    stagedRequests = new LinkedList<Request<?>>();
                }
                stagedRequests.add(request);                //新增到暫時儲存佇列中
                mWaitingRequests.put(cacheKey, stagedRequests);
                
            } else {                //第一次請求,應該是進入到這裡的
                // Insert 'null' queue for this cacheKey, indicating there is
                // now a request in
                // flight.
                //新增一個 null 佇列,表示有一個請求正在進行
                mWaitingRequests.put(cacheKey, null);                //新增到快取佇列中,那麼我們接下來重點檢視CacheDispatcher#run方法
                mCacheQueue.add(request);
            }            return request;
        }
    }

接下來就到 CacheDispatcher#run() 方法了,因為裡面有值了。

public void run() {
       
        Process.setThreadPriority(10);        //初始化快取型別有兩種目前:NoCache() 和 DiskBaseCache()
        this.mCache.initialize();        //巢狀了好多 while 迴圈
        while(true) {            while(true) {                while(true) {                    while(true) {                        try {                            //從快取佇列中取出,在之前第一篇文章時,沒展示下半部分,這次有請求就可以看下里面的邏輯了。
                            final Request<?> request = (Request)this.mCacheQueue.take();
                            request.addMarker("cache-queue-take");                            //請求未取消
                            if (request.isCanceled()) {
                                request.finish("cache-discard-canceled");
                            } else {                                //拿到快取結果,請求資訊都儲存一個叫Entry內部類中
                                Entry entry = this.mCache.get(request.getCacheKey());                                //有可能取出的快取為null
                                if (entry == null) {
                                    request.addMarker("cache-miss");                                    //如果清空了快取,那就重新新增到網路請求佇列中去
                                    this.mNetworkQueue.put(request);
                                } else if (!entry.isExpired()) {//判斷是否過期
                                    request.addMarker("cache-hit");                                    //拿到請求結果response
                                    Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
                                    request.addMarker("cache-hit-parsed");                                    //表示是否需要重新重新整理
                                    if (!entry.refreshNeeded()) {                                        //不需要的話就直接分發給主執行緒了
                                        this.mDelivery.postResponse(request, response);
                                    } else {                                        //需要重新整理,就重新進行網路請求
                                        request.addMarker("cache-hit-refresh-needed");
                                        request.setCacheEntry(entry);
                                        response.intermediate = true;                                        this.mDelivery.postResponse(request, response, new Runnable() {                                            public void run() {                                                try {                    ////需要重新整理,就重新進行網路請求                                              
                   CacheDispatcher.this.mNetworkQueue.put(request);
                                                } catch (InterruptedException var2) {
                                                    ;
                                                }

                                            }
                                        });
                                    }
                                } else {                                    //表示過期了,也重新進行請求
                                    request.addMarker("cache-hit-expired");
                                    request.setCacheEntry(entry);                                    this.mNetworkQueue.put(request);
                                }
                            }
                        } catch (InterruptedException var4) {                            if (this.mQuit) {                                return;
                            }
                        }

關於 CacheDispatcher#run 類我畫了一張圖示:

圖片描述

CacheDispatcher.png


從這裡我們知道,網路請求首先需要mCacheDispatcher 判斷是否已快取,若快取了則直接 postResponse 如果沒有,則重新進行網路請求,我們就直接新增到 mNetworkQueue 中,那第一次請求,肯定還未快取, 那我們下面就又可以看這個 NetworkDispatcher#run 方法了,因為此時佇列中有請求了,接下來我們再返回檢視:

NetworkDispatcher#run() 方法:

public void run() {        //設定執行緒優先順序
        Process.setThreadPriority(10);        while(true) {
            Request request;            while(true) {                try {                    //從這個網路請求佇列中中取出一條request
                    //第二次這裡有了,因為我們add 了 一個 request
                    request = (Request)this.mQueue.take();                    break;
                } catch (InterruptedException var4) {                    if (this.mQuit) {                        return;
                    }
                }
            }            //以下都是網路請求佇列有網路請求任務時執行
                request.addMarker("network-queue-take");                if (request.isCanceled()) {//判斷是否取消
                    request.finish("network-discard-cancelled");
                } else {                    //網路請求未取消
                    this.addTrafficStatsTag(request);                    //處理網路請求,得到NetworkResponse
                    NetworkResponse networkResponse = this.mNetwork.performRequest(request);                    //標識請求完成
                    request.addMarker("network-http-complete");                    if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                        request.finish("not-modified");
                    } else {                        //開始解析返回的結果,解析parseNetworkResponse可根據不同型別的方式進行解析,請看下圖:
                        Response<?> response = request.parseNetworkResponse(networkResponse);                        //標識解析完成
                        request.addMarker("network-parse-complete");                        //開始快取請求結果,判斷是否可以快取,預設可以
                        if (request.shouldCache() && response.cacheEntry != null) {                            this.mCache.put(request.getCacheKey(), response.cacheEntry);
                            request.addMarker("network-cache-written");
                        }                        //分發請求結果透過 mDelivery 完成
                        request.markDelivered();                        this.mDelivery.postResponse(request, response);
                    }
                }
    }

解析 有Json  Image String 等多種型別。

圖片描述

image.png


到此基本分析完畢。奉上一個整體流程圖,我在網上找到的,感覺還不錯:


圖片描述



作者:糖葫蘆_倩倩
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/200/viewspace-2821994/,如需轉載,請註明出處,否則將追究法律責任。

相關文章