Vollery源碼閱讀(二)

上節寫到關於 Vollery 的前半部分,須要查看的點擊 這裏 , 此次主要查看當咱們真正 add request 的時候作進一步查看。java

咱們仍是從使用的方法做爲咱們的切入點:緩存

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() 方法了,由於裏面有值了。post

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 類我畫了一張圖示: ui

CacheDispatcher.png

從這裏咱們知道,網絡請求首先須要mCacheDispatcher 判斷是否已緩存,若緩存了則直接 postResponse 若是沒有,則從新進行網絡請求,咱們就直接添加到 mNetworkQueue 中,那第一次請求,確定還未緩存, 那咱們下面就又能夠看這個 NetworkDispatcher#run 方法了,由於此時隊列中有請求了,接下來咱們再返回查看:this

NetworkDispatcher#run() 方法:url

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 等多種類型。 spa

image.png

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

image.png
相關文章
相關標籤/搜索