Android Volley

Filed Under: Android

In this tutorial, we’ll be discussing at length, an important networking library in our application, namely Android Volley. Android Volley library has been developed by Google. The first glimpses of it were seen in Google I/O 2013. Let’s see what it has in store!

Android Volley

Networking is a key component in most of the Android Applications today. Using an AsyncTask might not be the best option when we have too many networking requests to handle. AsyncTask can’t prioritize parallel/multiple requests in an orderly manner. Besides they have a lot of boilerplate code. Here’s where Android Volley library comes as a handy tool. It has some powerful features and is a lot faster than AsyncTask.

Advantages of Android Volley Library

  1. Automatic scheduling of all network requests.
  2. Multiple concurrent network connections.
  3. Requests queuing and prioritization.
  4. Caching responses. It supports memory and disk-based caches.
  5. Cancelling one or more requests.
  6. Built-in support for String, Images, JSONObject and JSONArray Requests.
  7. Ability to create custom requests.
  8. Built-in NetworkImageView widget to load images from a URL easily.
  9. Support for retrying requests.
  10. Powerful debugging and tracing tools to catch errors.

Getting Started with Android Volley

To integrate Volley in your Android Studio Project, you need to add the following dependency in your build.gradle file:


compile 'com.android.volley:volley:1.0.0'

Unlike Retrofit, which requires a bunch of libraries like OkHttp, Picasso for complete functionalities, Volley Library is much smaller in size.

Note: With the introduction of Android Studio 3.0 IDE the keyword compile is replaced by implementation in the dependencies. Both can be used interchangeably.

The Fundamental classes of Volley are listed below.

  • RequestQueue
  • Requests
  • Response

Android Volley RequestQueue

This is the basic building block of Volley. The name speaks for itself. A RequestQueue is used to queue all the requests and handle the responses. Also, it is responsible for managing the worker threads for parallel requests besides reading and writing to and from the cache. A RequestQueue works in a FIFO manner(First In First Out). At a time it can handle four requests simultaneously. A RequestQueue is instantiated in the following way in a class.


RequestQueue requestQueue = Volley.newRequestQueue(this);

this refers to the context. It can be activity or application’s context. The above code initializes the RequestQueue with a default set of parameters. We can initialize the RequestQueue with our own set of parameters as shown below.


RequestQueue mRequestQueue;

// Instantiate the cache
Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap

// Set up the network to use HttpURLConnection as the HTTP client.
Network network = new BasicNetwork(new HurlStack());

// Instantiate the RequestQueue with the cache and network.
mRequestQueue = new RequestQueue(cache, network);

// Start the queue
mRequestQueue.start();

We’ve initialized our own instances of Cache and Network with custom parameters.
Call the method mRequestQueue.stop() to stop the queue that’ll handle the requests.

Android Volley Request

Request instances are built to define a network request. These are used to support GET and POST requests.
Request class acts as the base class which can be extended to define a custom request.
Volley provides the following types of Requests built-in:

  • StringRequest
  • JsonObjectRequest
  • JsonArrayRequest
  • ImageRequest

Android Volley StringRequest

StringRequest is used when you want the response returned in the form of a String. You can then parse the response using Gson or JSON as per your requirement.
StringRequest has two forms of constructors as shown in the image below.
android volley library, android volley tutorial, android volley StringRequest
We’ll discuss the first constructor here.


StringRequest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener)
  • method : Expects an argument among GET, POST, PUT, DELETE.
  • url : URl to fetch the response at.
  • listener : Listens for a success response. We need to implement and override the following method in here.
    
    @Override
      public void onResponse(String response){
    
      //response parameter is of the same type as defined in the constructor.
     
      }
    
  • errorListener: Listens for an error response. We need to implement the following method in here.
    
    @Override
      public void onErrorResponse(VolleyError error){
      //handle your error here. We'll look at 
      }
    

A sample code snippet of a string request is given below.


RequestQueue queue = Volley.newRequestQueue(this);

StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    VolleyLog.wtf(response, "utf-8");

                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    VolleyLog.wtf(error.getMessage(), "utf-8");
                }
            });

queue.add(stringRequest);

The response or error will be delivered to the onResponse/onErrorResponse classes that we defined in our request above.
queue.add(stringRequest); is used to add the Request to the RequestQueue.
The code snippet written above can be simplified to improve the readability.


Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            VolleyLog.wtf(error.getMessage(), "utf-8");
        }
    };

    Response.Listener<String> responseListener = new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            VolleyLog.wtf(response);

        }
    };

StringRequest stringRequest = new StringRequest(Request.Method.GET, url, responseListener, errorListener);

The constructor looks much better now.
To send parameters in request body we need to override either the getParams() or getBody() method of the request class.
Additionally, we can override the getHeaders() and the getBodyContentType() methods too to specify the headers and content type formats respectively.
getHeaders() are useful for authentication.
To override the Request Method type from the first parameter, getMethod() is implemented.
The constructor with skeleton code of the above mentioned methods is given below.


StringRequest stringRequest = new StringRequest(Request.Method.GET, url, responseListener, errorListener){
        @Override
        public Map getParams() {
            Map params = new HashMap();

            params.put("key", "value");

            return params;
        }

        @Override
        public byte[] getBody() throws AuthFailureError {

            String requestBody = "";  //The request body goes in here.


            try {
                return requestBody.getBytes("utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", requestBody, "utf-8");
                return null;
            }
        }

        @Override
        public Map getHeaders() throws AuthFailureError {
            HashMap headers = new HashMap();
            headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
            String credentials = "sample:JournalDev@123";
            String auth = "Basic "
                        + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
            headers.put("Authorization",auth); //authentication
            return headers;
        }

        @Override
        public String getBodyContentType() {
            return "application/x-www-form-urlencoded; charset=utf-8";
        }

        @Override
        public int getMethod() {
             return Method.POST;
        }

    };

Parameters and headers are specified as a key-value pair in the getParams() and getHeaders() methods respectively.

Note: getParams() method is ignored when the request type is a GET. So to pass parameters we’ll need to concatenate them in the URL string as shown below.


String BASE_URL = "https://reqres.in";
String url = String.format(BASE_URL + "/api/users?page=%1$s", "2");

%1$s is used for the first param. %2$s, %3$s and so on for the second, third parameters.

Android Volley JsonObjectRequest

JsonObjectRequest is used to send and receive JSONObject from the server. It extends the class JsonRequest.
The two forms of constructors are given below.
android volley jsonrequest constructor
We’ll look at the second constructor here.


JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
                VolleyLog.wtf(response.toString());

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            VolleyLog.wtf(error.getMessage(), "utf-8");
        }
    });

queue.add(jsonObjectRequest)

An optional JSONObject can be passed as the request body in the second parameter of the constructor.
We’ve set it to null for now.

JsonObjectRequest can override the same set of methods (getHeaders(), getBodyContentType(), getBody(), getMethod()) like the StringRequest except getParams().

JsonObjectRequest is meant for passing a JSONObject with the request. Hence getParams() gets ignored.
Overriding getBody() isn’t neccessary in a JsonObjectRequest since passing a JSONObject as the second parameter does the same implicitly.

If you eventually override getBody(), the second parameter passed in the constructor would be ignored.
Since the Request type isn’t defined in the above constructor, the request would automatically identify the method(GET,POST, PUT or DELETE) from the url. To explicitily specify the method type we can override the getMethod()


JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, responseListener, errorListener){

        @Override
        public int getMethod() {
             return Method.POST; //This specifies the Method type to POST explicitly.
        }

        @Override
        public byte[] getBody() {

            //Building the response body here would ignore the JSONObject passed in the second parameter.
        }
    };

Android Volley JsonArrayRequest

JsonArrayRequest is used to send and retrieve JSONArray to and from the server. It extends the JsonRequest class and functions the same way as JsonObjectRequest class.
A JSONArrayRequest can’t handle a request that returns a JSONObject.
Following are the two forms of constructors.
android volley jsonarrayrequest constructor
Let’s look at the second constructor.


JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.POST, url, null, new Response.Listener<JSONArray>() {
        @Override
        public void onResponse(JSONArray response) {
            
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
                  VolleyLog.wtf(error.getMessage(), "utf-8");
            
        }
    });

Android Volley ImageRequest

Using ImageRequest is the classical and standard way to fetch images from a URL. An ImageRequest returns a Bitmap Object that we can eventually display in our ImageView.
Following are the two constructors present in the class.
android volley imagerequest

Let’s use the second constructor since the first one now stands deprecated.
Besides the url, response and error listeners, the constructor expects the width, height, scaleType and Config values for the bitmap.


RequestQueue queue = Volley.newRequestQueue(this);

ImageRequest imageRequest = new ImageRequest(IMAGE_URL, new Response.Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap response) {

                if (response != null) {
                    imageView.setImageBitmap(response);
                }

            }
        }, 200, 200, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.ARGB_8888, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                    VolleyLog.wtf(error.getMessage(), "utf-8");
            }
        });

queue.add(imageRequest);

The RequestQueue has a RequestFinishedListener. The listener gets triggered everytime a request in the queue is finished.


queue.addRequestFinishedListener(new RequestQueue.RequestFinishedListener<Object>() {

            @Override
            public void onRequestFinished(Request<Object> request) {
                try {
                    if (request.getCacheEntry() != null) {
                        String cacheValue = new String(request.getCacheEntry().data, "UTF-8");
                        Log.d(TAG, request.getCacheKey() + " " + cacheValue);

                    }
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        });

Android Volley Error Handling

onErrorResponse() passes an instance of VolleyError as we have seen above.
Following are the major types of errors that can be returned in the instance.

  • AuthFailureError: When the authentication fails.
  • NetworkError: Server Error, DNS issues etc.
  • NoConnectionError: When there is no internet connection.
  • ParseError: Generally returned in a JsonObjectRequest or JsonArrayRequest when the JSON response is malformed.
  • ServerError: The server responded with an error status code (401, 500 etc)
  • TimeoutError: When a request timeout occurs. Volley has a default timeout of 2.5 seconds.

Android Volley Cancelling Requests

Volley has a powerful API for canceling requests. Request cancellation is important in situations where the Activity needs to be destroyed. Cancellation of requests is possible using tags.


JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, responseListener, errorListener);
jsonObjectRequest.setTag("Sample");

JsonObjectRequest jsonObjectRequest2 = new JsonObjectRequest(url_2, null, responseListener, errorListener);
jsonObjectRequest2.setTag("No sample");

queue.add(jsonObjectRequest);
queue.add(jsonObjectRequest2);

queue.cancelAll("Sample"); //Cancels all requests with tag "Sample" present in the RequestQueue.

//Alternative way....

queue.cancelAll(new RequestQueue.RequestFilter() {
            @Override
            public boolean apply(Request<?> request) {
                return request.getTag().equals("Sample"); //requests with the condition true are cancelled.
            }
        });


Android Volley Prioritizing Requests

A priority can be set on each request present in the RequestQueue. Doing so the RequestQueue would run the requests based on the priorities instead of FIFO. A priority can be assigned by overriding the method getPriority() in the constructor. Following are the possible states:

  • Priority.LOW: Used to load images.
  • Priority.NORMAL: Default value.
  • Priority.HIGH: Used to load texts.
  • Priority.IMMEDIATE: Used in places like login/logout.

Following code snippet assigns priority to requests.


RequestQueue queue = Volley.newRequestQueue(this);

Response.Listener<JSONObject> jsonResponseListener = new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {

        }
    };

    Response.Listener<String> stringResponseListener = new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {

        }
    };

    Response.Listener imageResponseListener = new Response.Listener() {
        @Override
        public void onResponse(Bitmap response) {

        }
    };


    Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            VolleyLog.wtf(error.getMessage(), "utf-8");
        }
    };

StringRequest stringRequest = new StringRequest(Request.Method.GET, url, stringResponseListener, errorListener){
            @Override
            public Priority getPriority() {
                return Priority.IMMEDIATE;
            }};
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, jsonResponseListener, errorListener){
            @Override
            public Priority getPriority() {
                return Priority.HIGH;
            }};;

ImageRequest imageRequest = new ImageRequest(IMAGE_URL, imageResponseListener, 200, 200, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.ARGB_8888, errorListener){
            @Override
            public Priority getPriority() {
                return Priority.LOW;
            }};;

queue.add(imageRequest);
queue.add(jsonObjectRequest);
queue.add(stringRequest);

//Order of requests run : stringRequest > jsonRequest > imageRequest

Android Volley Caching

Caches are enabled by default for the above mentioned Request types. The response data is typically stored in the form of byte array

Disabling Cache


stringRequest.setShouldCache(false)

Accessing the Cache


String cacheValue = new String(stringRequest.getCacheEntry().data, "UTF-8");

//Accessing from the RequestQueue
String cacheValue = new String(queue.getCache().get(url).data, "UTF-8");

//The Request URL is stored in the cache key ...
String url = request.getCacheKey();

//Check other details in the cache.
stringRequest.getCacheEntry().isExpired() //checks if the cache is expired or not.
stringRequest.getCacheEntry().lastModified

Clearing cache


queue.getCache().remove(url); //removes cache for the specific url.

//clear all cache....
queue.getCache().clear();

Invalidate cache: Invalidating a cache would show the cached data until the new response is returned. That response would override the current cache.


queue.getCache().invalidate(url, true);

Android Volley ImageLoader and NetworkImageView

We’ve used an ImageRequest to retrieve an image bitmap from the response before.
Volley provides us with NetworkImageView widget that directly loads the image from the URL. Besides, it lets us set a default placeholder as well as an error drawable.
ImageLoader is responsible for loading the images using a BitmapLruCache().


<com.android.volley.toolbox.NetworkImageView
        android:id="@+id/networkImageView"
        android:layout_width="100dp"
        android:layout_height="100dp"/>

setImageFromUrl() method directly sets the image returned from the url onto the NetworkImageView instance. We need to pass the URL and ImageLoader instance in this method to fetch the image.



networkImageView.setDefaultImageResId(R.mipmap.ic_launcher);
networkImageView.setErrorImageResId(R.drawable.ic_error);

ImageLoader imageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache(64000)); //size is in Kb.

networkImageView.setImageUrl(IMAGE_URL, imageLoader);
// Loads the image with placeholder and error image
imageLoader.get(IMAGE_URL, ImageLoader.getImageListener(networkImageView, R.mipmap.ic_launcher, R.drawable.ic_error));

Note: To troubleshoot and log debug traces set the following line in your code.

VolleyLog.DEBUG = true;

We can create our own Custom Requests too by extending Request<T>. The two abstract methods parseNetworkResponse() and deliverResponse() need to be overriden.
This brings an end to this comprehensive tutorial on Volley. We’ll implement Volley in an application using the above-learned concepts in our next tutorial.

Reference: GitHub Page, API Doc

Comments

  1. Hori Revens says:

    Hello.. i have read your post about Volley and OkHttp. I just want to ask, which is the best between them? And why? Can you explain to me? 🙂

    Thx before

  2. shihab says:

    Well explained simply…

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages