1d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/* 2d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Copyright (C) 2011 The Android Open Source Project 3d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 4d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Licensed under the Apache License, Version 2.0 (the "License"); 5d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * you may not use this file except in compliance with the License. 6d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * You may obtain a copy of the License at 7d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 8d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * http://www.apache.org/licenses/LICENSE-2.0 9d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 10d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Unless required by applicable law or agreed to in writing, software 11d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * distributed under the License is distributed on an "AS IS" BASIS, 12d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * See the License for the specific language governing permissions and 14d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * limitations under the License. 15d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 16d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 17d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupackage com.android.volley; 18d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 19d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport android.os.Handler; 20d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport android.os.Looper; 21d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 2258f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabotimport java.util.ArrayList; 23d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.HashMap; 24d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.HashSet; 25d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.LinkedList; 2658f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabotimport java.util.List; 27d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Map; 28d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Queue; 29d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Set; 30d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.concurrent.PriorityBlockingQueue; 31d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.concurrent.atomic.AtomicInteger; 32d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 33d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/** 34d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * A request dispatch queue with a thread pool of dispatchers. 35d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 36d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Calling {@link #add(Request)} will enqueue the given Request for dispatch, 37d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * resolving from either cache or network on a worker thread, and then delivering 38d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * a parsed response on the main thread. 39d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 40d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupublic class RequestQueue { 41d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 4258f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot /** Callback interface for completed requests. */ 4358f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot public static interface RequestFinishedListener<T> { 4458f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot /** Called when a request has finished processing. */ 4558f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot public void onRequestFinished(Request<T> request); 4658f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot } 4758f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot 48d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** Used for generating monotonically-increasing sequence numbers for requests. */ 496772bce3d3322ccbcf6481545ffe895d5d401b39Jean-Baptiste Queru private AtomicInteger mSequenceGenerator = new AtomicInteger(); 50d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 51d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 52d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Staging area for requests that already have a duplicate request in flight. 53d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 54d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <ul> 55d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <li>containsKey(cacheKey) indicates that there is a request in flight for the given cache 56d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * key.</li> 57d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <li>get(cacheKey) returns waiting requests for the given cache key. The in flight request 58d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * is <em>not</em> contained in that list. Is null if no requests are staged.</li> 59d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * </ul> 60d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 6135d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick private final Map<String, Queue<Request<?>>> mWaitingRequests = 6235d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick new HashMap<String, Queue<Request<?>>>(); 63d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 64d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 65d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * The set of all requests currently being processed by this RequestQueue. A Request 66d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * will be in this set if it is waiting in any queue or currently being processed by 67d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * any dispatcher. 68d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 6935d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>(); 70d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 71d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** The cache triage queue. */ 7235d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick private final PriorityBlockingQueue<Request<?>> mCacheQueue = 7335d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick new PriorityBlockingQueue<Request<?>>(); 74d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 75d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** The queue of requests that are actually going out to the network. */ 7635d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick private final PriorityBlockingQueue<Request<?>> mNetworkQueue = 7735d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick new PriorityBlockingQueue<Request<?>>(); 78d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 79d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** Number of network request dispatcher threads to start. */ 80d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; 81d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 8235d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick /** Cache interface for retrieving and storing responses. */ 83d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private final Cache mCache; 84d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 85d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** Network interface for performing requests. */ 86d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private final Network mNetwork; 87d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 88d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** Response delivery mechanism. */ 89d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private final ResponseDelivery mDelivery; 90d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 91d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** The network dispatchers. */ 92d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private NetworkDispatcher[] mDispatchers; 93d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 94d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** The cache dispatcher. */ 95d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private CacheDispatcher mCacheDispatcher; 96d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 9758f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot private List<RequestFinishedListener> mFinishedListeners = 9858f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot new ArrayList<RequestFinishedListener>(); 9958f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot 100d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 101d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Creates the worker pool. Processing will not begin until {@link #start()} is called. 102d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 103d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param cache A Cache to use for persisting responses to disk 104d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param network A Network interface for performing HTTP requests 105d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param threadPoolSize Number of network dispatcher threads to create 106d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param delivery A ResponseDelivery interface for posting responses and errors 107d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 108d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public RequestQueue(Cache cache, Network network, int threadPoolSize, 109d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru ResponseDelivery delivery) { 110d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCache = cache; 111d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mNetwork = network; 112d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mDispatchers = new NetworkDispatcher[threadPoolSize]; 113d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mDelivery = delivery; 114d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 115d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 116d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 117d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Creates the worker pool. Processing will not begin until {@link #start()} is called. 118d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 119d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param cache A Cache to use for persisting responses to disk 120d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param network A Network interface for performing HTTP requests 121d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param threadPoolSize Number of network dispatcher threads to create 122d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 123d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public RequestQueue(Cache cache, Network network, int threadPoolSize) { 124d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru this(cache, network, threadPoolSize, 125d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru new ExecutorDelivery(new Handler(Looper.getMainLooper()))); 126d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 127d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 128d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 129d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Creates the worker pool. Processing will not begin until {@link #start()} is called. 130d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 131d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param cache A Cache to use for persisting responses to disk 132d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param network A Network interface for performing HTTP requests 133d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 134d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public RequestQueue(Cache cache, Network network) { 135d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE); 136d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 137d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 138d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 139d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Starts the dispatchers in this queue. 140d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 141d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public void start() { 142d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru stop(); // Make sure any currently running dispatchers are stopped. 143d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Create the cache dispatcher and start it. 144d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); 145d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCacheDispatcher.start(); 146d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 147d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Create network dispatchers (and corresponding threads) up to the pool size. 148d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru for (int i = 0; i < mDispatchers.length; i++) { 149d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, 150d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCache, mDelivery); 151d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mDispatchers[i] = networkDispatcher; 152d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru networkDispatcher.start(); 153d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 154d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 155d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 156d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 157d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Stops the cache and network dispatchers. 158d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 159d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public void stop() { 160d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (mCacheDispatcher != null) { 161d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCacheDispatcher.quit(); 162d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 163d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru for (int i = 0; i < mDispatchers.length; i++) { 164d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (mDispatchers[i] != null) { 165d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mDispatchers[i].quit(); 166d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 167d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 168d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 169d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 170d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 171d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Gets a sequence number. 172d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 1736772bce3d3322ccbcf6481545ffe895d5d401b39Jean-Baptiste Queru public int getSequenceNumber() { 1746772bce3d3322ccbcf6481545ffe895d5d401b39Jean-Baptiste Queru return mSequenceGenerator.incrementAndGet(); 175d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 176d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 177d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 1780acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton * Gets the {@link Cache} instance being used. 1790acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton */ 1800acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton public Cache getCache() { 1810acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton return mCache; 1820acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton } 1830acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton 1840acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton /** 185d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * A simple predicate or filter interface for Requests, for use by 186d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * {@link RequestQueue#cancelAll(RequestFilter)}. 187d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 188d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public interface RequestFilter { 189d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public boolean apply(Request<?> request); 190d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 191d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 192d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 193d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Cancels all requests in this queue for which the given filter applies. 194d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param filter The filtering function to use 195d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 196d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public void cancelAll(RequestFilter filter) { 197d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru synchronized (mCurrentRequests) { 198d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru for (Request<?> request : mCurrentRequests) { 199d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (filter.apply(request)) { 200d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru request.cancel(); 201d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 202d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 203d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 204d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 205d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 206d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 207d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Cancels all requests in this queue with the given tag. Tag must be non-null 208d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * and equality is by identity. 209d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 210d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public void cancelAll(final Object tag) { 211d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (tag == null) { 212d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru throw new IllegalArgumentException("Cannot cancelAll with a null tag"); 213d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 214d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru cancelAll(new RequestFilter() { 215d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru @Override 216d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public boolean apply(Request<?> request) { 217d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return request.getTag() == tag; 218d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 219d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru }); 220d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 221d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 222d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 223d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Adds a Request to the dispatch queue. 224d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param request The request to service 225d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @return The passed-in request 226d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 227393504e5d9aaf1c79c52df482b70e3f80ac50765Max Cai public <T> Request<T> add(Request<T> request) { 228d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Tag the request as belonging to this queue and add it to the set of current requests. 229d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru request.setRequestQueue(this); 230d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru synchronized (mCurrentRequests) { 231d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCurrentRequests.add(request); 232d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 233d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 234d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Process requests in the order they are added. 2356772bce3d3322ccbcf6481545ffe895d5d401b39Jean-Baptiste Queru request.setSequence(getSequenceNumber()); 236d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru request.addMarker("add-to-queue"); 237d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 238d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // If the request is uncacheable, skip the cache queue and go straight to the network. 239d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (!request.shouldCache()) { 240d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mNetworkQueue.add(request); 241d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return request; 242d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 243d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 244d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Insert request into stage if there's already a request with the same cache key in flight. 245d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru synchronized (mWaitingRequests) { 246d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru String cacheKey = request.getCacheKey(); 247d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (mWaitingRequests.containsKey(cacheKey)) { 248d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // There is already a request in flight. Queue up. 24935d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey); 250d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (stagedRequests == null) { 25135d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick stagedRequests = new LinkedList<Request<?>>(); 252d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 253d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru stagedRequests.add(request); 254d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mWaitingRequests.put(cacheKey, stagedRequests); 255d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (VolleyLog.DEBUG) { 256d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey); 257d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 258d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } else { 259d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Insert 'null' queue for this cacheKey, indicating there is now a request in 260d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // flight. 261d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mWaitingRequests.put(cacheKey, null); 262d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCacheQueue.add(request); 263d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 264d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return request; 265d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 266d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 267d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 268d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 269d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Called from {@link Request#finish(String)}, indicating that processing of the given request 270d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * has finished. 271d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 272d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <p>Releases waiting requests for <code>request.getCacheKey()</code> if 273d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <code>request.shouldCache()</code>.</p> 274d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 27558f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot <T> void finish(Request<T> request) { 276d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Remove from the set of requests currently being processed. 277d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru synchronized (mCurrentRequests) { 278d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCurrentRequests.remove(request); 279d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 28058f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot synchronized (mFinishedListeners) { 28158f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot for (RequestFinishedListener<T> listener : mFinishedListeners) { 28258f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot listener.onRequestFinished(request); 28358f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot } 28458f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot } 285d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 286d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (request.shouldCache()) { 287d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru synchronized (mWaitingRequests) { 288d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru String cacheKey = request.getCacheKey(); 28935d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick Queue<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey); 290d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (waitingRequests != null) { 291d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (VolleyLog.DEBUG) { 292d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.", 293d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru waitingRequests.size(), cacheKey); 294d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 295d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Process all queued up requests. They won't be considered as in flight, but 296d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // that's not a problem as the cache has been primed by 'request'. 297d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCacheQueue.addAll(waitingRequests); 298d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 299d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 300d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 301d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 30258f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot 30358f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot public <T> void addRequestFinishedListener(RequestFinishedListener<T> listener) { 30458f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot synchronized (mFinishedListeners) { 30558f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot mFinishedListeners.add(listener); 30658f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot } 30758f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot } 30858f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot 30958f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot /** 31058f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot * Remove a RequestFinishedListener. Has no effect if listener was not previously added. 31158f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot */ 31258f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot public <T> void removeRequestFinishedListener(RequestFinishedListener<T> listener) { 31358f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot synchronized (mFinishedListeners) { 31458f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot mFinishedListeners.remove(listener); 31558f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot } 31658f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot } 317d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru} 318