Volley, a Networking Library for Android
This article was updated on 21st December, 2016. Specifically: new entry, updated deprecated code and added a new section for image loading.
Networking with Volley in Android
Networking has been around since day zero of mobile technologies and Android is not different. What has changed is the way network operations are handled. The focus of networking libraries such as Volley has been the automation of the network operations.
Until HoneyComb, network calls ran from the main thread and in subsequent Android versions, network requests executed asynchronously from the main thread. To make a network call, a developer needs to implement an Asynctask
in a different thread from the main application thread or a NetworkOnMainThreadException
will be thrown.
A short overview of Volley
Volley is a networking library for Android that manages network requests. It bundles the most important features you’ll need, such as accessing JSON APIs, loading images and String requests in an easier-to-use package.
By using Volley for network operations you avoid the standard way to handle networking, HttpURLConnection
. Another reason is asynchronicity. Volley handles asynchronicity by itself, there is no need to create Asynctask
manually.
Based on the documentation, the core of every network operation performed by Volley is the RequestQueue
. Working with Volley is handled by creating a RequestQueue
and passing it Request
objects. The RequestQueue
manages worker threads for running the network operations, reading from and writing to the cache, and parsing responses.
Volley offers a variety of features, as mentioned in its documentation:
- Automatic scheduling of network requests.
- Multiple concurrent network connections.
- Caching.
- Request prioritization.
- Cancellation of ongoing API requests.
These are the core benefits that this library provides and the main focus of this article.
Import Volley, add Permissions
Before getting started with Volley, you need to configure your Android project.
Create a new Android project. Open build.gradle(Module: app)
and add the following dependency.
dependencies {
//...
compile 'com.android.volley:volley:1.0.0'
}
In AndroidManifest.xml
add the internet permission.
<uses-permission android:name="android.permission.INTERNET" />
Standard Network Requests
As I previously mentioned, the core of every network operation performed by Volley is the RequestQueue
. Every request made to the network is passed to the RequestQueue
trough Request
objects.
There are three types of requests, JSON requests, Image requests and String requests. I will go through each of these types with explanations and code examples.
For now, in MainActivity
’s onCreate()
method, initiate the RequestQueue
.
RequestQueue requestQueue;
@Override
protected void onCreate(Bundle savedInstanceState) {
//...
requestQueue = Volley.newRequestQueue(this); // 'this' is the Context
}
JSON Requests
Volley has Requests for JSONObject
and JSONArray
. The structure of JSONRequest and most of the request classes included in Volley uses constructors like the following.
JsonObjectRequest request JsonObjectRequest(RequestMethod, URL, null, new ResponseListener(), new ErrorListener());
Parameters passed into the constructor:
RequestMethod
(GET, POST, PUT, DELETE, etc.)URL
: String of the URL of the required objectJSONObject
: An optional object posted with the request, null if there is no object postedResponseListener
: Response Listener, whose callback method will contain the responseErrorListener
: AResponse.ErrorListener
whose callback method will contain any problem with the request.
The following code snippets are the complete implementation of both JsonObjectRequest
and JsonArrayRequest
respectively.
/*Json Request*/
String url = "https://json_url/";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
//add request to queue
requestQueue.add(jsonObjectRequest);
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, url, null,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
//add request to queue
requestQueue.add(jsonArrayRequest);
Now that I’ve shown how to receive JSON data in Android, let’s see how to post data with Volley.
The request is the same format as receiving JSON data with the exception that you must specify a JSONObject
posted with the request and request headers for sending data from the client to server side.
/*Post data*/
Map<String, String> jsonParams = new HashMap<String, String>();
jsonParams.put("email", "user@gmail.com");
jsonParams.put("username", "user");
jsonParams.put("password", "pass");
JsonObjectRequest postRequest = new JsonObjectRequest( Request.Method.POST, URL,
new JSONObject(jsonParams),
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// Handle Error
}
}) {
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json; charset=utf-8");
headers.put("User-agent", System.getProperty("http.agent"));
return headers;
}
};
requestQueue.add(postRequest);
Note that the request headers might have to change depending on the development use case.
String Request
This type of request is used to retrieve data from a server as a String.
/*String Request*/
String url = "https://string_url/";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
//add request to queue
requestQueue.add(stringRequest);
The structure of the StringRequest
contains a request method (POST or GET), a URL to the String source, a Response.Listener
and a Response.ErrorListener
. Pretty much the same as the JsonRequest
.
Image Request
Volley offers a few ways to load images in Android. I will go through all of them to explain their differences and provide some code samples.
ImageRequest
ImageRequest
is a way to load images for getting an image at a given URL. The structure of this network call is similar to the other requests previously presented.
The following code is an example of an ImageRequest
to load an image into an ImageView
.
int maxWidth = ...;
int maxHeight = ...;
String URL = "http://image_url.png";
ImageRequest imageRequest = new ImageRequest(URL, new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
// Assign the response to an ImageView
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap(response);
}
}, maxWidth, maxHeight, null);
//add request to queue
requestQueue.add(imageRequest);
The structure of the ImageRequest
is straightforward. It needs the image’s URL, a Response Listener, whose callback method will contain the image Bitmap as a response, a maxWidth
and maxHeight
, a Config format to decode the bitmap to, and a Response.ErrorListener
for any response errors. Add the request to the RequestQueue
and the Android runtime will handle the rest.
ImageLoader
ImageLoader
is a helper class to handle loading and caching images from remote URLs. This request is useful for a large number of ImageRequest
. According to the documentation ImageLoader
provides an in-memory cache to sit in front of the normal Volley cache, which is important to prevent flickering.
NetworkImageView
NetworkImageView
is an efficient way to replace ImageView
when images are being loaded from the network.
The following code snippets provide an implementation of both the two last sections of image loading with Volley. The following VolleySingleton
class is an implementation of a RequestQueue
. This singleton class has caching capabilities with in-memory LRU cache. The LruCache
is set up to store up to 30 elements.
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import android.util.Log;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;
public class VolleySingleton {
private static VolleySingleton singletonInstance = null;
private RequestQueue requestQueue;
private ImageLoader imageLoader;
private VolleySingleton(Context context) {
requestQueue = Volley.newRequestQueue(context);
imageLoader = new ImageLoader(this.requestQueue, new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(30);
//30 -> the maximum number of entries in the cache.
public void putBitmap(String url, Bitmap bitmap) {
lruCache.put(url, bitmap);
Log.d("CachedItems", String.valueOf(lruCache.size()));
}
public Bitmap getBitmap(String url) {
return lruCache.get(url);
}
});
}
public static VolleySingleton getInstance(Context context) {
if (singletonInstance == null) {
singletonInstance = new VolleySingleton(context);
}
return singletonInstance;
}
public RequestQueue getRequestQueue() {
return this.requestQueue;
}
public ImageLoader getImageLoader() {
return this.imageLoader;
}
}
Now that the VolleySingleton
class is setup, lets load an image into a NetworkImageView
. But first, add an instance int the Activity’s layout file. Here is an example:
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/networkImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Finally, load an image into the NetworkImageView
. In the in MainActivity
’s onCreate()
method add this code.
private ImageLoader imageLoader;
private NetworkImageView imageView;
private static final String IMAGE_URL = "https://the_images_url.jpg";
@Override
protected void onCreate(Bundle savedInstanceState) {
//...
imageLoader = VolleySingleton.getInstance(getApplicationContext()).getImageLoader();
imageView = (NetworkImageView) findViewById(R.id.networkImageView);
imageView.setImageUrl(IMAGE_URL, imageLoader);
}
To make sure the cache works properly, I added a Log
statement in the VolleySingleton
class. Run the project and check the Log in Android Studio. Each time a new image is cached the device prints out a number of cached items.
Request Prioritization
Handling network requests means prioritizing what’s needed and how fast the response is needed since networking is a real time operation.
Volley processes the requests from higher priorities to lower priorities, in first-in-first-out order. There is no setPriority()
method, so to prioritize a request, some work is needed.
Here is an example of a custom JsonObjectRequest
class that can make priority requests. The focus of this class is on the overridden getPriority()
method. When the request is added to the queue this method will return the priority assigned to it by setPriority()
, or will return Priority.HIGH
assigned inside the class, but it won’t search for a priority outside this class.
The same structure applies to all the other request types.
public class CustomPriorityRequest extends JsonObjectRequest {
Priority priority = Priority.HIGH;
public CustomPriorityRequest(int method, String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
super(method, url, jsonRequest, listener, errorListener);
}
public CustomPriorityRequest(String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
super(url, jsonRequest, listener, errorListener);
}
@Override
public Priority getPriority() {
return priority;
}
public void setPriority(Priority p){
priority = p;
}
}
Making a request with this new class is the same as the standard requests. You have the ability to set a request priority before adding it to the queue.
CustomPriorityRequest customPriorityRequest = new CustomPriorityRequest(
Request.Method.GET, URL, null,
new Response.Listener<JSONObject>(),
new Response.ErrorListener());
customPriorityRequest.setPriority(Request.Priority.IMMEDIATE);
requestQueue.add(customPriorityRequest);
Some available priorities are: Priority.LOW, Priority.NORMAL, Priority.HIGH and Priority.IMMEDIATE.
Cancel Requests
Another useful tool in Volley is the ability to cancel the requests. Canceling requests is useful when the user closes the app or performs an action that results in not using the responses of the Volley requests. There is no sense executing the remaining requests in the queue, so we cancel them in the onStop()
method.
The easiest way to cancel requests in Volley is to add a tag to the request and when the queued requests need to be canceled, call the cancelAll()
method. This will cancel all the requests specified with that specific tag.
request.setTag("TAG");
requestQueue.cancelAll("TAG");
Once cancelAll()
executes from the main thread, the remaining responses will not be delivered.