1# Set up a RequestQueue 2 3The previous lesson showed you how to use the convenience method 4`Volley.newRequestQueue` to set up a `RequestQueue`, taking advantage of 5Volley's default behaviors. This lesson walks you through the explicit steps of creating a 6`RequestQueue`, to allow you to supply your own custom behavior. 7 8This lesson also describes the recommended practice of creating a `RequestQueue` 9as a singleton, which makes the `RequestQueue` last the lifetime of your app. 10 11## Set up a network and cache 12 13A `RequestQueue` needs two things to do its job: a network to perform transport 14of the requests, and a cache to handle caching. There are standard implementations of these 15available in the Volley toolbox: `DiskBasedCache` provides a one-file-per-response 16cache with an in-memory index, and `BasicNetwork` provides a network transport based 17on your preferred HTTP client. 18 19`BasicNetwork` is Volley's default network implementation. A `BasicNetwork` 20must be initialized with the HTTP client your app is using to connect to the network. 21Typically this is an 22[`HttpURLConnection`](https://developer.android.com/reference/java/net/HttpURLConnection). 23 24This snippet shows you the steps involved in setting up a `RequestQueue`: 25 26*Kotlin* 27 28```kotlin 29// Instantiate the cache 30val cache = DiskBasedCache(cacheDir, 1024 * 1024) // 1MB cap 31 32// Set up the network to use HttpURLConnection as the HTTP client. 33val network = BasicNetwork(HurlStack()) 34 35// Instantiate the RequestQueue with the cache and network. Start the queue. 36val requestQueue = RequestQueue(cache, network).apply { 37 start() 38} 39 40val url = "http://www.example.com" 41 42// Formulate the request and handle the response. 43val stringRequest = StringRequest(Request.Method.GET, url, 44 Response.Listener<String> { response -> 45 // Do something with the response 46 }, 47 Response.ErrorListener { error -> 48 // Handle error 49 textView.text = "ERROR: %s".format(error.toString()) 50 }) 51 52// Add the request to the RequestQueue. 53requestQueue.add(stringRequest) 54 55// ... 56``` 57 58*Java* 59 60```java 61RequestQueue requestQueue; 62 63// Instantiate the cache 64Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap 65 66// Set up the network to use HttpURLConnection as the HTTP client. 67Network network = new BasicNetwork(new HurlStack()); 68 69// Instantiate the RequestQueue with the cache and network. 70requestQueue = new RequestQueue(cache, network); 71 72// Start the queue 73requestQueue.start(); 74 75String url = "http://www.example.com"; 76 77// Formulate the request and handle the response. 78StringRequest stringRequest = new StringRequest(Request.Method.GET, url, 79 new Response.Listener<String>() { 80 @Override 81 public void onResponse(String response) { 82 // Do something with the response 83 } 84}, 85 new Response.ErrorListener() { 86 @Override 87 public void onErrorResponse(VolleyError error) { 88 // Handle error 89 } 90}); 91 92// Add the request to the RequestQueue. 93requestQueue.add(stringRequest); 94 95// ... 96``` 97 98If you just need to make a one-time request and don't want to leave the thread pool 99around, you can create the `RequestQueue` wherever you need it and call `stop()` on the 100`RequestQueue` once your response or error has come back, using the 101`Volley.newRequestQueue()` method described in [Sending a Simple Request](./simple.md). 102But the more common use case is to create the `RequestQueue` as a 103singleton to keep it running for the lifetime of your app, as described in the next section. 104 105## Use a singleton pattern 106 107If your application makes constant use of the network, it's probably most efficient to 108set up a single instance of `RequestQueue` that will last the lifetime of your app. 109You can achieve this in various ways. The recommended approach is to implement a singleton 110class that encapsulates `RequestQueue` and other Volley functionality. Another approach is to 111subclass [`Application`](https://developer.android.com/reference/android/app/Application) and 112set up the `RequestQueue` in 113[`Application.onCreate()`](https://developer.android.com/reference/android/app/Application#onCreate()). 114But this approach is discouraged; a static singleton can provide the same functionality in a 115more modular way. 116 117A key concept is that the `RequestQueue` must be instantiated with the 118[`Application`](https://developer.android.com/reference/android/app/Application) context, not an 119[`Activity`](https://developer.android.com/reference/android/app/Activity) context. This 120ensures that the `RequestQueue` will last for the lifetime of your app, instead of 121being recreated every time the activity is recreated (for example, when the user 122rotates the device). 123 124Here is an example of a singleton class that provides `RequestQueue` and 125`ImageLoader` functionality: 126 127*Kotlin* 128 129```kotlin 130class MySingleton constructor(context: Context) { 131 companion object { 132 @Volatile 133 private var INSTANCE: MySingleton? = null 134 fun getInstance(context: Context) = 135 INSTANCE ?: synchronized(this) { 136 INSTANCE ?: MySingleton(context).also { 137 INSTANCE = it 138 } 139 } 140 } 141 val imageLoader: ImageLoader by lazy { 142 ImageLoader(requestQueue, 143 object : ImageLoader.ImageCache { 144 private val cache = LruCache<String, Bitmap>(20) 145 override fun getBitmap(url: String): Bitmap? { 146 return cache.get(url) 147 } 148 override fun putBitmap(url: String, bitmap: Bitmap) { 149 cache.put(url, bitmap) 150 } 151 }) 152 } 153 val requestQueue: RequestQueue by lazy { 154 // applicationContext is key, it keeps you from leaking the 155 // Activity or BroadcastReceiver if someone passes one in. 156 Volley.newRequestQueue(context.applicationContext) 157 } 158 fun <T> addToRequestQueue(req: Request<T>) { 159 requestQueue.add(req) 160 } 161} 162``` 163 164*Java* 165 166```java 167public class MySingleton { 168 private static MySingleton instance; 169 private RequestQueue requestQueue; 170 private ImageLoader imageLoader; 171 private static Context ctx; 172 173 private MySingleton(Context context) { 174 ctx = context; 175 requestQueue = getRequestQueue(); 176 177 imageLoader = new ImageLoader(requestQueue, 178 new ImageLoader.ImageCache() { 179 private final LruCache<String, Bitmap> 180 cache = new LruCache<String, Bitmap>(20); 181 182 @Override 183 public Bitmap getBitmap(String url) { 184 return cache.get(url); 185 } 186 187 @Override 188 public void putBitmap(String url, Bitmap bitmap) { 189 cache.put(url, bitmap); 190 } 191 }); 192 } 193 194 public static synchronized MySingleton getInstance(Context context) { 195 if (instance == null) { 196 instance = new MySingleton(context); 197 } 198 return instance; 199 } 200 201 public RequestQueue getRequestQueue() { 202 if (requestQueue == null) { 203 // getApplicationContext() is key, it keeps you from leaking the 204 // Activity or BroadcastReceiver if someone passes one in. 205 requestQueue = Volley.newRequestQueue(ctx.getApplicationContext()); 206 } 207 return requestQueue; 208 } 209 210 public <T> void addToRequestQueue(Request<T> req) { 211 getRequestQueue().add(req); 212 } 213 214 public ImageLoader getImageLoader() { 215 return imageLoader; 216 } 217} 218``` 219 220Here are some examples of performing `RequestQueue` operations using the singleton 221class: 222 223*Kotlin* 224 225```kotlin 226// Get a RequestQueue 227val queue = MySingleton.getInstance(this.applicationContext).requestQueue 228 229// ... 230 231// Add a request (in this example, called stringRequest) to your RequestQueue. 232MySingleton.getInstance(this).addToRequestQueue(stringRequest) 233``` 234 235*Java* 236 237```java 238// Get a RequestQueue 239RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()). 240 getRequestQueue(); 241 242// ... 243 244// Add a request (in this example, called stringRequest) to your RequestQueue. 245MySingleton.getInstance(this).addToRequestQueue(stringRequest); 246``` 247