Android Volley is a HTTP library for Android app developers. Previous to the Volley library, making a standard HTTP request was kind of tedious, involving both an HttpUrlConnection and (hopefully) an AsyncTask.

When using the Volley library, you don’t have to worry about implementing anything – Volley does this for you.
Volley can be seen as an abstracted layer above HttpUrlConnection, and is a great library for developers short on time. In other words, practically everyone.

Volley is developed by Google, and is available on GitHub.

How does the Volley library work?

Android volley library tutorialBefore diving into the implementation and actual method calls, let’s have a look at what the Volley library actually is. By getting a pretty good grasp of how it works behind the scenes, it is a whole lot easier to use the library as intended.
Generally, whenever you want to use any library (not limited to Android development), you should have a look at the source code – or at least the documentation.

By having a look at the source code and the documentation, it is clear that the library actually uses the native HttpUrlConnection behind the scenes. For some of you, this may be obvious.

With that said, I think it’s an important thing to mention, so programmers just starting out can get a feel for how libraries actually works. The “magic” provided by many libraries is in fact just a an abstracted implementation of the very same objects you would use if you were to do it manually!

We now know how the Volley library communicate through Http connections. But what about the UI thread?
For those unfamiliar with this term, the “UI thread” is the User Interface thread.

If we were to do network operations directly on the UI thread, the user interface would freeze until the network operation was finished. This is almost always not what you want – you want the to perform the network operations on a separate thread, or background task if you will. This way, the user can still interact with the application, while data is being downloaded in the background.

The Volley library do all this work for us, with the use of Threads. Each HTTP request is executed in a separate thread, and when the data has been downloaded, the caller get notified through an interface, or callback interface of you will.

With that said, there is a whole lot more going on behind the scenes, but that’s not something we’ll need to dive into right now. Let’s implement the Volley library!

How to use the Volley library in Android

The first thing one should do is to set up a RequestQueue. The RequestQueue in Volley manages background (worker) threads,  and is responsible for delivering the network results back to the main thread of your application.

Note that the RequestQueue should be implemented using a Singleton Pattern. In short, this means that you’ll have only one single instance of the RequestQueue throughout the whole lifecycle of your application. If you’re unfamiliar with the Singleton Pattern, you can have a read about it here.

The RequestQueue will handle all the network operations for you. All you have to do, is to provide it with a Request. In this tutorial we’ll be working with a JsonRequest, since this is something you’ll see alot if you’re working against an API.

A JsonRequest is constructed with four parameters:

  1. The method type (POST, GET, DELETE etc.)
  2. The URL
  3. JSON-object to post to the URL. This can be null if you’re not posting anything.
  4. A Response.Listener, which is fired when the network operation is done.

Finally, when you have constructed both your RequestQueue and Request, all you have to do is call the add-method of your RequestQueue, passing in your Request.

Let’s implement some usage examples in an imaginary application. Instead of going with unrealistic examples (which alot of tutorials do!), we’ll go with a real-life example.
For the rest of this tutorial, assume that we’re developing a movie database application. The use-cases for our imaginary application is as follows:

  1. The user should be able to list popular movies (GET).
  2. The user should be able to rate movies (POST).
  3. The user should be able to delete ratings (DELETE).

The first thing we’ll do is to create a class containing the RequestQueue, built with a Singleton Pattern. We’ll call this class ApiManager.

import android.content.Context;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;

/**
 * Class containing a RequestQueue, built with the Singleton Pattern.
 * This class is responsible for calls against the API.
 *
 * @author Anders Engen Olsen.com
 */
public class ApiManager {

    /**
     * Singleton
     */
    private static ApiManager apiManager = null;
    /**
     * Imaginary class, responsible for reading JSON.
     */
    private JsonParser jsonParser;
    /**
     * Activity context
     */
    private Context context;
    /**
     * RequestQueue Volley-library
     */
    private RequestQueue queue;

    /**
     * Private constructor. Called from getInstance().
     *
     * @param context Activity-context
     * @see #getInstance(Context)
     */
    private ApiManager(Context context) {
        this.context = context;
        jsonParser = new JsonParser(context);
        queue = Volley.newRequestQueue(context);
    }

    /**
     * Initalizing an ApiManager object if null.
     *
     * @param context Activity-context
     * @return Singleton object
     */
    public static synchronized ApiManager getInstance(Context context) {
        if (apiManager == null)
            apiManager = new ApiManager(context);

        return apiManager;
    }

}

We can now obtain an instance of the ApiManager by calling ApiManager.getInstance(this) in our activities.

Before implementing the methods to solve the actual use cases, we have one problem that needs to be addressed. How will the RequestQueue communicate with our activities?
We’ll solve this by creating an interface, which will be fired when the RequestQueue is done.  We’ll call this interface ApiListener.

/**
 * Generic interface, fired when data is downloaded from API.
 *
 * @author Anders Engen Olsen
 */
public interface ApiListener<AnyType> {

    /**
     * Returning result from the Api.
     *
     * @param result Api result
     */
    void onSuccess(AnyType result);

    /**
     * Returning result from Api.
     *
     * @param result Api result
     */
    void onError(String result);
}

It’s time to implement the three methods which will solve our use-cases.

    
     /**
     * Fetching popular movies
     *
     * @param listener listener, fired when downloaded
     */
    public void getPopularMovies(final ApiListener<ArrayList<Movie>> listener) {

        String url = "URL TO THE API";

        // Construction a JsonObjectRequest.
        // This means that we expect to receive a JsonObject from the API.
        final JsonObjectRequest json = new JsonObjectRequest(
                Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                // This indicates that the call was successfull.

                // Creating an ArrayList with Movie-objects from our imaginary JsonParser.
                ArrayList<Movie> movies = jsonParser.parseMovies(response);

                // Firing our interface-method, returning the movies to the activity
                listener.onSuccess(movies);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // This indicates that the call wasn't successful.
                // We'll return a String to our activity
                listener.onError("Error connecting to the API");
            }
        }
        );

        // Adding the response to our requestqueue
        queue.add(json);
    }
    
     /**
     * Adding rating to a movie
     * We assume we rate by a post request to the url:
     * URL-TO-THE-API/rate/movieId
     *
     * @param listener listener, fired when downloaded
     */
    public void rateMovie(int rating, int movieId, final ApiListener<String> listener) {

        String url = "URL-TO-THE-API/rate/" + movieId;

        // Creating the JSON to post to the API
        JSONObject json = new JSONObject();

        try {
            json.put("RATING", rating);
        } catch (JSONException err) {
            listener.onError("Error occurred!");
            return;
        }

        // Construction a JsonObjectRequest.
        // This means that we expect to receive a JsonObject from the API.
        final JsonObjectRequest jsonRequest = new JsonObjectRequest(
                Request.Method.POST, url, json, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                // This indicates that the call was successfull.

                // Reading the response with our imaginary JsonParser
                String responseString = jsonParser.parseResponse(response);
                // Firing our interface-method, notifying the activity
                listener.onSuccess(responseString);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // This indicates that the call wasn't successful.
                // We'll return a String to our activity
                listener.onError("Error connecting to the API");
            }
        }
        );

        // Adding the response to our requestqueue
        queue.add(jsonRequest);
    }
    
     /**
     * Adding rating to a movie.
     * We assume that the rating is deleted by sending a DELETE request to this URL:
     * URL-TO-THE-API/ratings/movieId
     *
     * @param listener listener, fired when downloaded
     */
    public void deleteRating(int movieId, final ApiListener<String> listener) {

        String url = "URL-TO-THE-API/ratings/" + movieId;

        // Construction a JsonObjectRequest.
        // This means that we expect to receive a JsonObject from the API.
        // Notice that we pass null -> We don't want to post anything to the API
        final JsonObjectRequest jsonRequest = new JsonObjectRequest(
                Request.Method.DELETE, url, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                // This indicates that the call was successfull.

                // Reading the response with our imaginary JsonParser
                String responseString = jsonParser.parseResponse(response);
                // Firing our interface-method, notifying the activity
                listener.onSuccess(responseString);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // This indicates that the call wasn't successful.
                // We'll return a String to our activity
                listener.onError("Error connecting to the API");
            }
        }
        );

        // Adding the response to our requestqueue
        queue.add(jsonRequest);
    }

The final ApiManager class now looks like this:

import android.content.Context;
import android.graphics.Movie;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

/**
 * Class containing a RequestQueue, built with the Singleton Pattern.
 * This class is responsible for calls against the API.
 *
 * @author Anders Engen Olsen.com
 */
public class ApiManager {

    /**
     * Singleton
     */
    private static ApiManager apiManager = null;
    /**
     * Imaginary class, responsible for reading JSON.
     */
    private JsonParser jsonParser;
    /**
     * Activity context
     */
    private Context context;
    /**
     * RequestQueue Volley-library
     */
    private RequestQueue queue;

    /**
     * Private constructor. Called from getInstance().
     *
     * @param context Activity-context
     * @see #getInstance(Context)
     */
    private ApiManager(Context context) {
        this.context = context;
        jsonParser = new JsonParser(context);
        queue = Volley.newRequestQueue(context);
    }

    /**
     * Initalizing a ApiManager object if null.
     *
     * @param context Activity-context
     * @return Singleton object
     */
    public static synchronized ApiManager getInstance(Context context) {
        if (apiManager == null)
            apiManager = new ApiManager(context);

        return apiManager;
    }

    /**
     * Adding rating to a movie.
     * We assume that the rating is deleted by sending a DELETE request to this URL:
     * URL-TO-THE-API/ratings/movieId
     *
     * @param listener listener, fired when downloaded
     */
    public void deleteRating(int movieId, final ApiListener<String> listener) {

        String url = "URL-TO-THE-API/ratings/" + movieId;

        // Construction a JsonObjectRequest.
        // This means that we expect to receive a JsonObject from the API.
        // Notice that we pass null -> We don't want to post anything to the API
        final JsonObjectRequest jsonRequest = new JsonObjectRequest(
                Request.Method.DELETE, url, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                // This indicates that the call was successfull.

                // Reading the response with our imaginary JsonParser
                String responseString = jsonParser.parseResponse(response);
                // Firing our interface-method, notifying the activity
                listener.onSuccess(responseString);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // This indicates that the call wasn't successful.
                // We'll return a String to our activity
                listener.onError("Error connecting to the API");
            }
        }
        );

        // Adding the response to our requestqueue
        queue.add(jsonRequest);
    }

    /**
     * Fetching popular movies
     *
     * @param listener listener, fired when downloaded
     */
    public void getPopularMovies(final ApiListener<ArrayList<Movie>> listener) {

        String url = "URL TO THE API";

        // Construction a JsonObjectRequest.
        // This means that we expect to receive a JsonObject from the API.
        final JsonObjectRequest json = new JsonObjectRequest(
                Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                // This indicates that the call was successfull.

                // Creating an ArrayList with Movie-objects from our imaginary JsonParser.
                ArrayList<Movie> movies = jsonParser.parseMovies(response);

                // Firing our interface-method, returning the movies to the activity
                listener.onSuccess(movies);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // This indicates that the call wasn't successful.
                // We'll return a String to our activity
                listener.onError("Error connecting to the API");
            }
        }
        );

        // Adding the response to our requestqueue
        queue.add(json);
    }

    /**
     * Adding rating to a movie
     * We assume we rate by a post request to the url:
     * URL-TO-THE-API/rate/movieId
     *
     * @param listener listener, fired when downloaded
     */
    public void rateMovie(int rating, int movieId, final ApiListener<String> listener) {

        String url = "URL-TO-THE-API/rate/" + movieId;

        // Creating the JSON to post to the API
        JSONObject json = new JSONObject();

        try {
            json.put("RATING", rating);
        } catch (JSONException err) {
            listener.onError("Error occurred!");
            return;
        }

        // Construction a JsonObjectRequest.
        // This means that we expect to receive a JsonObject from the API.
        final JsonObjectRequest jsonRequest = new JsonObjectRequest(
                Request.Method.POST, url, json, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                // This indicates that the call was successfull.

                // Reading the response with our imaginary JsonParser
                String responseString = jsonParser.parseResponse(response);
                // Firing our interface-method, notifying the activity
                listener.onSuccess(responseString);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // This indicates that the call wasn't successful.
                // We'll return a String to our activity
                listener.onError("Error connecting to the API");
            }
        }
        );

        // Adding the response to our requestqueue
        queue.add(jsonRequest);
    }
}

Now that we’re done with the logic, all that’s left to do is to implement this in our activities.
The following code stub shows how you would make use of the ApiManager class.

        

        // Receiving the Singleton-instance of the ApiManager
        ApiManager apiManager = ApiManager.getInstance(this);

        // Fetching the an ArrayList with popular movies
        apiManager.getPopularMovies(new ApiListener<ArrayList<Movie>>() {
            @Override
            public void onSuccess(ArrayList<Movie> result) {
                // Updating a local ArrayList called popularMovies
                popularMovies = result;
            }

            @Override
            public void onError(String result) {
                Toast.makeText(MyActivity.this, result, Toast.LENGTH_SHORT).show();
            }
        });

        // Adding rating to a movie. Adding rating 10 to movieId 1000
        apiManager.rateMovie(10, 1000, new ApiListener<String>() {
            @Override
            public void onSuccess(String result) {
                Toast.makeText(MyActivity.this, result, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(String result) {
                Toast.makeText(MyActivity.this, result, Toast.LENGTH_SHORT).show();
            }
        });

        // Deleting the rating of movie 1000
        apiManager.deleteRating(1000, new ApiListener<String>() {
            @Override
            public void onSuccess(String result) {
                Toast.makeText(MyActivity.this, result, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(String result) {
                Toast.makeText(MyActivity.this, result, Toast.LENGTH_SHORT).show();
            }
        });

Summary

You’ve now seen a few examples on how to use the Volley-library to perform network request in your Android application.
In this tutorial we stuck with using the JsonObjectRequest. There is also possible to use both StringRequest and ImageRequest.
For further documentation, please refer to the official GitHub-repository for Volley.