天天看點

Android中的volley_6_volley的核心RequestQueue類

demo下載下傳:http://download.csdn.net/detail/vvzhouruifeng/8747599

可以說RequestQueue是volley最為核心的類了,其他一切都是圍繞着該類進行運轉的。之前講述的Volley類,其主要工作就是建立RequestQueue的執行個體并start()。

用最概括的話來描述RequestQueue就是:彙集所有Request并分發給緩存和網絡排程線程。

RequestQueue的工作流程是這樣的:

1.建立RequestQueue執行個體後,調用start()方法,此時就建立一個緩存排程線程和預設的四個網絡排程線程,并開啟線程。

2.當有新的request後,調用add()方法将request添加到請求隊列中,然後判斷該request是否需要緩存,如果不需要緩存就添加到網絡請求隊列中;如果需要緩存,先判斷在等待隊列中是否存在,如果已經存在則将該請求添加進等待隊列,如果等待隊列中不存在,則先在等待隊列中push一個cachekey,value為空,在添加進緩存隊列。(在等待隊列中先push一個cachekey,其value為空,表示已經有個request曾要進入等待隊列,但是進入了緩存隊列,那麼後邊相同的request就進入到等待隊列中吧。)

3.此時request已經明顯有了歸宿:緩存請求隊列、網絡請求隊列和等待隊列

4.而在start()内開啟的緩存排程線程和網絡排程線程會從緩存請求隊列和網絡請求隊列中取出request進行執行。

5.可以根據tag來關閉一個或多個request,需要調用cancelAll()方法。

6.當一個request執行完畢後,需要調用RequestQueue的finish()方法,在該方法内,先将request從請求隊列中移除,然後再從等待隊列中擷取所有相同的request并存放到緩存請求隊列中。

有了上邊總體的概述,在逐漸看下代碼:

1.建立RequestQueue執行個體後,調用start()方法,此時就建立一個緩存排程線程和預設的四個網絡排程線程,并開啟線程。

/**
	 * Starts the dispatchers in this queue.
	 * 重要方法:
	 * 1.開啟緩存排程線程
	 * 2.開啟網絡排程線程
	 */
	public void start() {
		stop(); // Make sure any currently running dispatchers are stopped.
		// 建立一個新的緩存排程線程,并将緩存請求隊列和網絡請求隊列傳遞進去,還有緩存和響應傳遞機制
		mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue,
				mCache, mDelivery);
		// 啟動緩存排程線程
		mCacheDispatcher.start();
		//開啟網絡排程線程,預設四個
		for (int i = 0; i < mDispatchers.length; i++) {
			NetworkDispatcher networkDispatcher = new NetworkDispatcher(
					mNetworkQueue, mNetwork, mCache, mDelivery);
			mDispatchers[i] = networkDispatcher;
			networkDispatcher.start();
		}
	}
           

2.當有新的request後,調用add()方法将request添加到請求隊列中,然後判斷該request是否需要緩存,如果不需要緩存就添加到網絡請求隊列中;如果需要緩存,先判斷在等待隊列中是否存在,如果已經存在則将該請求添加進等待隊列,如果等待隊列中不存在,則先在等待隊列中push一個cachekey,value為空,在添加進緩存隊列。(在等待隊列中先push一個cachekey,其value為空,表示已經有個request曾要進入等待隊列,但是進入了緩存隊列,那麼後邊相同的request就進入到等待隊列中吧。)

3.此時request已經明顯有了歸宿:緩存請求隊列、網絡請求隊列和等待隊列

4.而在start()内開啟的緩存排程線程和網絡排程線程會從緩存請求隊列和網絡請求隊列中取出request進行執行。

/**
	 * 将一個請求添加到請求隊列中
	 */
	public Request add(Request request) {
		request.setRequestQueue(this);
		// 添加到目前正在處理的請求隊列中
		synchronized (mCurrentRequests) {
			mCurrentRequests.add(request);
		}
		// Process requests in the order they are added.給請求設定請求序列号
		request.setSequence(getSequenceNumber());
		request.addMarker("add-to-queue");
		// to the network. 如果該請求不需要被緩存 那麼就直接添加到網絡請求隊列中
		if (!request.shouldCache()) {
			mNetworkQueue.add(request);
			return request;
		}
		//對于需要緩存的請求,需要放入等待隊列中
		synchronized (mWaitingRequests) {
			String cacheKey = request.getCacheKey();
			// 如果等待隊列中包含該請求
			if (mWaitingRequests.containsKey(cacheKey)) {
				// There is already a request in flight. Queue up.
				// 取出該請求的對應key對應的所有請求的隊列,這裡面存放的都是相同key的請求
				Queue<Request> stagedRequests = mWaitingRequests.get(cacheKey);
				// 如果為空
				if (stagedRequests == null) {
					// 就先建立一個集合用于存放請求
					stagedRequests = new LinkedList<Request>();
				}
				// 将該請求添加到集合中
				stagedRequests.add(request);
				// 重新存放到等待隊列中
				mWaitingRequests.put(cacheKey, stagedRequests);
				if (VolleyLog.DEBUG) {
					VolleyLog
							.v("Request for cacheKey=%s is in flight, putting on hold.",
									cacheKey);
				}
			} else {
				// 如果等待隊列中不存在,那麼就将key存入,等以後如果有相同的request那麼可以随時存放到等待隊列中,這裡就是為什麼要判斷if
				mWaitingRequests.put(cacheKey, null);
				// 既然已經到這裡了(上面的 if (!request.shouldCache())
				// ),那麼該請求肯定是需要緩存的,是以将其添加到緩存中
				mCacheQueue.add(request);
			}
			return request;
		}
	}
           

5.可以根據tag來關閉一個或多個request,需要調用cancelAll()方法。

/**
	 * 取消目前請求集合中所有符合條件的請求。 filter 參數表示可以按照自定義的過濾器過濾需要取消的請求。 tag
	 * 表示按照Request.setTag設定好的 tag 取消請求,比如同屬于某個 Activity 的
	 */
	public void cancelAll(RequestFilter filter) {
		// 周遊目前所有正在請求還沒有完成的請求
		synchronized (mCurrentRequests) {
			for (Request<?> request : mCurrentRequests) {
				// 如果請求的tag與給定的tag一緻,傳回true
				if (filter.apply(request)) {
					// 那麼取消目前請求
					request.cancel();
				}
			}
		}
	}

	/**
	 * 取消目前請求集合中所有符合條件的請求。 filter 參數表示可以按照自定義的過濾器過濾需要取消的請求。 tag
	 * 表示按照Request.setTag設定好的 tag 取消請求,比如同屬于某個 Activity 的
	 */
	public void cancelAll(final Object tag) {
		if (tag == null) {
			throw new IllegalArgumentException(
					"Cannot cancelAll with a null tag");
		}
		cancelAll(new RequestFilter() {
			@Override
			public boolean apply(Request<?> request) {
				// 實作過濾接口,該方法傳回值,表示給定tag是否與請求的tag一緻,如果一緻傳回true
				return request.getTag() == tag;
			}
		});
	}
           

6.當一個request執行完畢後,需要調用RequestQueue的finish()方法,在該方法内,先将request從請求隊列中移除,然後再從等待隊列中擷取所有相同的request并存放到緩存請求隊列中。

/**
	 * 告訴請求隊列,這個請求已經完成了。這個方法是在request内的finish方法調用的(注意請求完成(finish)和請求取消(cancel)
	 * 是不同的概念,完成表示已經發送完網絡請求并且拿回了資料,取消表示正在發送網絡請求或拿資料但是還沒完成)
	 * 
	 * (1). 首先從正在進行中請求集合mCurrentRequests中移除該請求。 (2).
	 * 然後查找請求等待集合mWaitingRequests中是否存在等待的請求
	 * ,如果存在,則将等待隊列移除,并将等待隊列所有的請求添加到緩存請求隊列中,讓緩存請求處理線程CacheDispatcher自動處理。
	 */
	void finish(Request request) {
		synchronized (mCurrentRequests) {
			// 在目前對隊列中将該請求給移除
			mCurrentRequests.remove(request);
		}

		if (request.shouldCache()) {
			// 如果該請求是可以被緩存的
			synchronized (mWaitingRequests) {
				String cacheKey = request.getCacheKey();
				// 從等待隊列中擷取該key對應的所有的請求
				Queue<Request> waitingRequests = mWaitingRequests
						.remove(cacheKey);
				if (waitingRequests != null) {
					if (VolleyLog.DEBUG) {
						VolleyLog
								.v("Releasing %d waiting requests for cacheKey=%s.",
										waitingRequests.size(), cacheKey);
					}
					// 'request'.為什麼要添加到緩存隊列中,這是因為當一個請求已經完成,并且擷取到了響應,就會将該請求标記為已完成也就是說需要再目前的請求隊列中finish掉該請求,而在等待隊列中存在的那些相同url的請求,就不需要再次發送網絡請求了
					// ,而認為是可以擷取之前的請求的資料,是以需要将這些相同的請求從等待隊列中移除,添加到緩存隊列中,這樣這些請求就會直接從緩存隊列中擷取資料,而不用再去發送網絡請求了
					mCacheQueue.addAll(waitingRequests);
				}
			}
		}
	}
           

OK,RequestQueue就了解到這裡。