Android Volley Tutorial

Filed Under: Android

In this android volley tutorial, we’ll be implementing the Volley library in our application. If you aren’t aware of the features of Volley, we recommend you to read this article before proceeding ahead.

Android Volley

Network Requests in a Volley are added to a RequestQueue. Instead of creating a new instance of RequestQueue every time, we follow the singleton pattern by creating a single instance of RequestQueue throughout our application.

In the application below, we’ll be implementing GET and POST StringRequest and JsonObjectRequests. We’ll use Gson library to parse the response and display the results in a RecyclerView.

Furthermore, we’ll implement a CustomRequest and load images from a URL in the ImageView.

Android Volley Tutorial Project Structure

android volley tutorial project structure

Android Volley Gradle Dependencies

Before we get onto the coding aspect of this tutorial, add the following dependencies in your build.gradle file.


compile 'com.android.support:cardview-v7:26.1.0'
    compile 'com.android.support:recyclerview-v7:26.1.0'
    compile 'com.android.support:design:26.1.0'
    compile 'com.google.code.gson:gson:2.8.0'
    compile 'com.android.volley:volley:1.0.0'

Android Volley Example Code

Layout – activity_main.xml
The code for the activity_main.xml layout that holds the UI for the MainActivity.java is given below.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.journaldev.volley.RecyclerViewActivity">

    <Button
        android:id="@+id/btnImageLoader"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/networkImageView"
        android:layout_alignStart="@+id/networkImageView"
        android:layout_below="@+id/networkImageView"
        android:layout_marginTop="16dp"
        android:text="LOAD IMAGE" />

    <Button
        android:id="@+id/btnImageRequest"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/btnImageLoader"
        android:layout_alignBottom="@+id/btnImageLoader"
        android:layout_marginLeft="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_toEndOf="@+id/imageView"
        android:layout_toRightOf="@+id/imageView"
        android:text="IMAGE REQUEST" />

    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/networkImageView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_below="@+id/imageView"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:layout_marginTop="8dp" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="8dp" />


    <Button
        android:id="@+id/btnGET"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignEnd="@+id/btnPOST"
        android:layout_alignLeft="@+id/btnPOST"
        android:layout_alignRight="@+id/btnPOST"
        android:layout_alignStart="@+id/btnPOST"
        android:layout_centerVertical="true"
        android:text="GET String JSON" />

    <Button
        android:id="@+id/btnPOST"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btnGET"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="8dp"
        android:text="POST String JSON" />


    <Button
        android:id="@+id/btnCustomRequest"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignEnd="@+id/btnPOST"
        android:layout_alignLeft="@+id/btnPOST"
        android:layout_alignRight="@+id/btnPOST"
        android:layout_alignStart="@+id/btnPOST"
        android:layout_below="@+id/btnPOST"
        android:layout_marginTop="8dp"
        android:text="CUSTOM REQUEST" />

</RelativeLayout>

SingletonRequestQueue.java


package com.journaldev.volley;

import android.content.Context;

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


public class SingletonRequestQueue {

    private static SingletonRequestQueue mInstance;
    private Context mContext;
    private RequestQueue mRequestQueue;

    private SingletonRequestQueue(Context context) {
        mContext = context;
        mRequestQueue = getRequestQueue();
    }

    public static synchronized SingletonRequestQueue getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new SingletonRequestQueue(context);
        }
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(mContext);
        }
        return mRequestQueue;
    }
}

getInstance() and getRequestQueue() methods create an instance of SingletonRequestQueue and RequestQueue respectively for the first time and re-use it everywhere.

Linking the layout to the MainActivity.java


public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button btnGET, btnPOST, btnImageLoader, btnCustomRequest, btnImageRequest;
    NetworkImageView networkImageView;
    ImageView imageView;
    ArrayList<UserList.UserDataList> mUserDataList = new ArrayList<>();
    String BASE_URL = "https://reqres.in";
    String IMAGE_URL = "https://www.android.com/static/2016/img/share/oreo-lg.jpg";
    int numberOfRequestsCompleted;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnGET = findViewById(R.id.btnGET);
        btnPOST = findViewById(R.id.btnPOST);
        btnImageLoader = findViewById(R.id.btnImageLoader);
        btnImageRequest = findViewById(R.id.btnImageRequest);
        btnCustomRequest = findViewById(R.id.btnCustomRequest);
        networkImageView = findViewById(R.id.networkImageView);
        imageView = findViewById(R.id.imageView);
        btnGET.setOnClickListener(this);
        btnPOST.setOnClickListener(this);
        btnImageLoader.setOnClickListener(this);
        btnCustomRequest.setOnClickListener(this);
        btnImageRequest.setOnClickListener(this);

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

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnGET:
                GETStringAndJSONRequest("2", "4");
                break;
            case R.id.btnPOST:
                POSTStringAndJSONRequest();
            case R.id.btnImageLoader:
                imageLoader();
            case R.id.btnImageRequest:
                imageRequest();
            case R.id.btnCustomRequest:
                customRequest();
                break;
        }
    }
}

There are 5 buttons for GET, POST, ImageLoader, ImageRequest, CustomRequest processing. Each of the features are triggered in the onClickListener separately.

We’ll look at each of the methods separately

  • GETStringAndJSONRequest()
  • POSTStringAndJSONRequest()
  • imageLoader()
  • imageRequest()
  • customRequest()

We’ll be using the REST API available at www.reqres.in.

The UserList.java class is the POJO class for serialising the response using Gson.

UserList.java


package com.journaldev.volley;

import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.List;

public class UserList implements Serializable {

    @SerializedName("page")
    public Integer page;
    @SerializedName("per_page")
    public Integer perPage;
    @SerializedName("total")
    public Integer total;
    @SerializedName("total_pages")
    public Integer totalPages;
    @SerializedName("data")
    public List<UserDataList> userDataList;

    public class UserDataList implements Serializable {

        @SerializedName("id")
        public Integer id;
        @SerializedName("first_name")
        public String first_name;
        @SerializedName("last_name")
        public String last_name;
        @SerializedName("avatar")
        public String avatar;

    }
}

The above class implements Serializable since an instance of it would passed as Bundle in Intents

Let’s look at the methods triggered by the Button click in the MainActivity.java that encapsulate a Volley Request.

GETStringAndJSONRequest()


Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            if (error instanceof NetworkError) {
                Toast.makeText(getApplicationContext(), "No network available", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(getApplicationContext(), error.toString(), Toast.LENGTH_LONG).show();
            }
        }
    };

private void GETStringAndJSONRequest(String page_1, String page_2) {
        mUserDataList.clear();
        numberOfRequestsCompleted = 0;
        VolleyLog.DEBUG = true;
        RequestQueue queue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();
        String uri_page_one = String.format(BASE_URL + "/api/users?page=%1$s", page_1);
        final String uri_page_two = String.format(BASE_URL + "/api/users?page=%1$s", page_2);

        StringRequest stringRequest = new StringRequest(Request.Method.GET, uri_page_one, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {

                VolleyLog.wtf(response, "utf-8");
                GsonBuilder builder = new GsonBuilder();
                Gson mGson = builder.create();
                UserList userList = mGson.fromJson(response, UserList.class);
                mUserDataList.addAll(userList.userDataList);
                ++numberOfRequestsCompleted;

            }
        }, errorListener) {

            @Override
            public Priority getPriority() {
                return Priority.LOW;
            }

        };

        queue.add(stringRequest);


        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(uri_page_two, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {

                VolleyLog.wtf(response.toString(), "utf-8");
                GsonBuilder builder = new GsonBuilder();
                Gson mGson = builder.create();

                UserList userList = mGson.fromJson(response.toString(), UserList.class);
                mUserDataList.addAll(userList.userDataList);
                ++numberOfRequestsCompleted;

            }
        }, errorListener) {

            @Override
            public String getBodyContentType() {
                return "application/json";
            }

            @Override
            public Priority getPriority() {
                return Priority.IMMEDIATE;
            }
        };

        queue.add(jsonObjectRequest);


        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");
                       VolleyLog.d(request.getCacheKey() + " " + cacheValue);

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

                if (numberOfRequestsCompleted == 2) {
                    numberOfRequestsCompleted = 0;
                    startActivity(new Intent(MainActivity.this, RecyclerViewActivity.class).putExtra("users", mUserDataList));
                }
            }
        });

    }

Important points to note in the above code:

  1. We’ve created an instance of ErrorListener that’ll be used throughout the Activity.
  2. We’ve chained two requests in the RequestQueue.
  3. The first Request is a StringRequest. page acts as a URL encoded parameter in the API /api/users?. The response is a JSONObject that’s serialized with Gson. We’ve set the priority of the StringRequest to low. Thus, this request should finish at last(in cases when the response from the server is quick, the priority won’t work).
  4. The second Request is a JsonObjectRequest. Since it is a GET request, we’ve set the request body as null(check the second parameter). Priority is set to Immediate. Thus the JsonObjectRequest should complete first.
  5. We join the Lists returned from both the requests in mUserDataList ArrayList.
  6. Inside the addRequestFinishedListener callback listener, we check if both the requests are over(by checking the numberOfRequestsCompleted counter.
  7. Besides, inside addRequestFinishedListener callback, we can retrieve the response from the Cache.Entry
  8. Try setting setShouldCache() to false on the Requests and you find the response in the cache.
  9. Finally the user data list retrieved from both the requests is passed to the RecyclerViewActivity.java. This is where we’ll populate the ArrayList in a RecyclerView.

Let’s look at the RecyclerViewActivity and layout code.

Layout – activity_recyclerview.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.journaldev.volley.RecyclerViewActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.constraint.ConstraintLayout>

RecyclerViewActivity.java


package com.journaldev.volley;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;

public class RecyclerViewActivity extends AppCompatActivity {

    RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview);

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setHasFixedSize(true);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));


        ArrayList userDataLists = (ArrayList) getIntent().getSerializableExtra("users");


        RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, userDataLists);
        recyclerView.setAdapter(adapter);

    }
}

The layout for each RecyclerView row is defined in recyclerview_row.xml.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="60dp">


        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent">

            <com.android.volley.toolbox.NetworkImageView
                android:id="@+id/imgNetwork"
                android:layout_width="48dp"
                android:layout_centerVertical="true"
                android:layout_height="48dp" />


            <TextView
                android:id="@+id/txtLabel"
                android:layout_toRightOf="@+id/imgNetwork"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_gravity="center"
                android:gravity="center" />

        </RelativeLayout>

    </android.support.v7.widget.CardView>

</RelativeLayout>

RecyclerViewAdapter.java


package com.journaldev.volley;

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v7.widget.RecyclerView;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.NetworkImageView;
import java.util.List;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.CustomRecyclerView> {

    private List<UserList.UserDataList> itemList;

    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;


    public RecyclerViewAdapter(Context context, List<UserList.UserDataList> itemList) {
        this.itemList = itemList;
        mRequestQueue = SingletonRequestQueue.getInstance(context).getRequestQueue();
        mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {
            private final LruCache<String, Bitmap> mCache = new LruCache<>(10);

            public void putBitmap(String url, Bitmap bitmap) {
                mCache.put(url, bitmap);
            }

            public Bitmap getBitmap(String url) {
                return mCache.get(url);
            }
        });
    }

    @Override
    public CustomRecyclerView onCreateViewHolder(ViewGroup parent, int viewType) {
        View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_row, null);
        CustomRecyclerView rcv = new CustomRecyclerView(layoutView);
        return rcv;
    }

    @Override
    public void onBindViewHolder(CustomRecyclerView holder, int position) {

        UserList.UserDataList myData = itemList.get(position);
        holder.txtLabel.setText(myData.first_name + " " + myData.last_name);
        holder.avatar.setImageUrl(myData.avatar, mImageLoader);


    }

    @Override
    public int getItemCount() {
        return this.itemList.size();
    }

    public class CustomRecyclerView extends RecyclerView.ViewHolder {
        TextView txtLabel;
        NetworkImageView avatar;

        CustomRecyclerView(View itemView) {
            super(itemView);
            txtLabel = itemView.findViewById(R.id.txtLabel);
            avatar = itemView.findViewById(R.id.imgNetwork);
        }
    }
}

We’ve initialized an ImageLoader that’ll display the Image from the URL in the NetworkImageView for each row.
The LRU cache is used for caching the image by implementing an ImageCache. The argument inside the LruCache constructor is the number of cache entries limit.

POSTStringAndJSONRequest()
This method would chain multiple POST requests in a RequestQueue.


    private void POSTStringAndJSONRequest() {

        RequestQueue queue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();

        VolleyLog.DEBUG = true;
        String uri = BASE_URL + "/api/users";

        StringRequest stringRequest = new StringRequest(Request.Method.POST, uri, new Response.Listener() {
            @Override
            public void onResponse(String response) {
                VolleyLog.wtf(response, "utf-8");
                Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();

            }
        }, errorListener) {
            @Override
            public Priority getPriority() {
                return Priority.LOW;
            }

            @Override
            public Map getParams() {
                Map params = new HashMap();

                params.put("name", "Anupam");
                params.put("job", "Android Developer");


                return params;
            }

            @Override
            public Map getHeaders() throws AuthFailureError {
                HashMap headers = new HashMap();
                headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
                return headers;
            }

        };


        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("name", "JournalDev.com");
            jsonObject.put("job", "To teach you the best");
        } catch (JSONException e) {
            e.printStackTrace();
        }


        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(uri, jsonObject, new Response.Listener() {
            @Override
            public void onResponse(JSONObject response) {
                VolleyLog.wtf(response.toString(), "utf-8");
                Toast.makeText(getApplicationContext(), response.toString(), Toast.LENGTH_LONG).show();

            }
        }, errorListener) {

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

            @Override
            public Priority getPriority() {
                return Priority.NORMAL;
            }
        };


        StringRequest stringRequestPOSTJSON = new StringRequest(Request.Method.POST, uri, new Response.Listener() {
            @Override
            public void onResponse(String response) {
                VolleyLog.wtf(response);
                Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();

            }
        }, errorListener) {
            @Override
            public Priority getPriority() {
                return Priority.HIGH;
            }

            @Override
            public Map getHeaders() throws AuthFailureError {
                HashMap headers = new HashMap();
                headers.put("Content-Type", "application/json; charset=utf-8");
                return headers;
            }

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

                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject.put("name", "Android Tutorials");
                    jsonObject.put("job", "To implement Volley in an Android Application.");
                } catch (JSONException e) {
                    e.printStackTrace();
                }

                String requestBody = jsonObject.toString();


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


        };
        
        queue.add(stringRequest);
        queue.add(jsonObjectRequest);
        queue.add(stringRequestPOSTJSON);


    }
  • stringRequest – To POST parameters in a StringRequest, we need to override getParams() and pass the parameters as a key value pair.
  • jsonObjectRequest – To POST parameters in a JsonObjectRequest we pass the parameters inside a JSONObject and set them in the second parameter of the constructor.
  • stringRequestPOSTJSON – To POST a JSON request body in a StringRequest, we override the method getBody().

imageLoader()


private void imageLoader() {
        RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();

        ImageLoader imageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {
            private final LruCache mCache = new LruCache(10);

            public void putBitmap(String url, Bitmap bitmap) {
                mCache.put(url, bitmap);
            }

            public Bitmap getBitmap(String url) {
                return mCache.get(url);
            }
        });

        networkImageView.setImageUrl(IMAGE_URL, imageLoader);
        imageLoader.get(IMAGE_URL, ImageLoader.getImageListener(
                networkImageView, R.mipmap.ic_launcher, R.drawable.ic_error));
    }

getImageListener() handles the functionality of showing a default image until the network response is received, at which point it will switch to either the actual image or the error image.
The arguments passed inside the listener are the view’s instance, default image drawable, error image drawable.

imageRequest()


private void imageRequest() {
        RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();
        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, errorListener);

        mRequestQueue.add(imageRequest);
    }

customRequest()


private void customRequest() {
        mUserDataList.clear();
        RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();
        String url = String.format(BASE_URL + "/api/users?page=%1$s", "2");

        HashMap headers = new HashMap();
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");

        GsonRequest gsonRequest = new GsonRequest(url, UserList.class, headers, new Response.Listener() {
            @Override
            public void onResponse(UserList response) {
                mUserDataList.addAll(response.userDataList);
                startActivity(new Intent(MainActivity.this, RecyclerViewActivity.class).putExtra("users", mUserDataList));

            }
        }, errorListener);

        mRequestQueue.add(gsonRequest);

    }

We’ve created a CustomRequest named GsonRequest that serializes and converts the response into the POJO class internally. Also, the CustomRequest takes the headers as a constructor argument too.

Let’s see how the GsonRequest.java class is written.

GsonRequest.java


package com.journaldev.volley;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

import java.io.UnsupportedEncodingException;
import java.util.Map;


public class GsonRequest extends Request {
    private final Gson gson = new Gson();
    private final Class myClass;
    private final Map headers;
    private final Map params;
    private final Response.Listener listener;

    public GsonRequest(String url, Class myClass, Map headers,
                       Response.Listener listener, Response.ErrorListener errorListener) {
        super(Method.GET, url, errorListener);
        this.myClass = myClass;
        this.headers = headers;
        this.params = null;
        this.listener = listener;
    }

    public GsonRequest(int type, String url, Class myClass, Map headers,
                       Map params,
                       Response.Listener listener, Response.ErrorListener errorListener) {
        super(type, url, errorListener);
        this.myClass = myClass;
        this.headers = headers;
        this.params = params;
        this.listener = listener;
    }

    @Override
    public Map getHeaders() throws AuthFailureError {
        return headers != null ? headers : super.getHeaders();
    }

    @Override
    protected Map getParams() throws AuthFailureError {
        return params != null ? params : super.getParams();
    }

    @Override
    protected void deliverResponse(T response) {
        if(null != listener){
            listener.onResponse(response);
        }
    }

    @Override
    protected Response parseNetworkResponse(NetworkResponse response) {
        try {


            String json = new String(
                    response.data, HttpHeaderParser.parseCharset(response.headers));
            return Response.success(
                    gson.fromJson(json, myClass), HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JsonSyntaxException e) {
            return Response.error(new ParseError(e));
        }
    }
}

A Custom Request requires the two methods, parseNetworkResponse and deliverResponse to be overridden.

The parseNetworkResponse parses the raw network response. In the above code, Gson library serializes it into a POJO class. The result is available in the deliverResponse method.

In the deliverResponse method, we’ve triggered a callback to the Response.Listener’s onResponse method.

Hasn’t the above GsonRequest Custom Request simplified and generalized the code for storing a response in a POJO class.

The full source code for the MainActivity.java class is given below.


package com.journaldev.volley;

import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.LruCache;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageRequest;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.NetworkImageView;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

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

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;



public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button btnGET, btnPOST, btnImageLoader, btnCustomRequest, btnImageRequest;
    NetworkImageView networkImageView;
    ImageView imageView;
    ArrayList<UserList.UserDataList> mUserDataList = new ArrayList<>();
    String BASE_URL = "https://reqres.in";
    String IMAGE_URL = "https://www.android.com/static/2016/img/share/oreo-lg.jpg";
    int numberOfRequestsCompleted;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnGET = findViewById(R.id.btnGET);
        btnPOST = findViewById(R.id.btnPOST);
        btnImageLoader = findViewById(R.id.btnImageLoader);
        btnImageRequest = findViewById(R.id.btnImageRequest);
        btnCustomRequest = findViewById(R.id.btnCustomRequest);
        networkImageView = findViewById(R.id.networkImageView);
        imageView = findViewById(R.id.imageView);
        btnGET.setOnClickListener(this);
        btnPOST.setOnClickListener(this);
        btnImageLoader.setOnClickListener(this);
        btnCustomRequest.setOnClickListener(this);
        btnImageRequest.setOnClickListener(this);

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

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnGET:
                GETStringAndJSONRequest("2", "4");
                break;
            case R.id.btnPOST:
                POSTStringAndJSONRequest();
                break;
            case R.id.btnImageLoader:
                imageLoader();
                break;
            case R.id.btnImageRequest:
                imageRequest();
                break;
            case R.id.btnCustomRequest:
                customRequest();
                break;
        }
    }

    private void GETStringAndJSONRequest(String page_1, String page_2) {
        mUserDataList.clear();
        numberOfRequestsCompleted = 0;
        VolleyLog.DEBUG = true;
        RequestQueue queue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();
        String uri_page_one = String.format(BASE_URL + "/api/users?page=%1$s", page_1);
        final String uri_page_two = String.format(BASE_URL + "/api/users?page=%1$s", page_2);

        StringRequest stringRequest = new StringRequest(Request.Method.GET, uri_page_one, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {

                VolleyLog.wtf(response, "utf-8");
                GsonBuilder builder = new GsonBuilder();
                Gson mGson = builder.create();
                UserList userList = mGson.fromJson(response, UserList.class);
                mUserDataList.addAll(userList.userDataList);
                ++numberOfRequestsCompleted;

            }
        }, errorListener) {

            @Override
            public Priority getPriority() {
                return Priority.LOW;
            }

        };

        queue.add(stringRequest);


        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(uri_page_two, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {

                VolleyLog.wtf(response.toString(), "utf-8");
                GsonBuilder builder = new GsonBuilder();
                Gson mGson = builder.create();

                UserList userList = mGson.fromJson(response.toString(), UserList.class);
                mUserDataList.addAll(userList.userDataList);
                ++numberOfRequestsCompleted;

            }
        }, errorListener) {

            @Override
            public String getBodyContentType() {
                return "application/json";
            }

            @Override
            public Priority getPriority() {
                return Priority.IMMEDIATE;
            }
        };

        queue.add(jsonObjectRequest);


        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("API123", request.getCacheKey() + " " + cacheValue);

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

                if (numberOfRequestsCompleted == 2) {
                    numberOfRequestsCompleted = 0;
                    startActivity(new Intent(MainActivity.this, RecyclerViewActivity.class).putExtra("users", mUserDataList));
                }
            }
        });

    }

    private void POSTStringAndJSONRequest() {

        RequestQueue queue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();

        VolleyLog.DEBUG = true;
        String uri = BASE_URL + "/api/users";

        StringRequest stringRequest = new StringRequest(Request.Method.POST, uri, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                VolleyLog.wtf(response);
                Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();

            }
        }, errorListener) {
            @Override
            public Priority getPriority() {
                return Priority.LOW;
            }

            @Override
            public Map<String, String> getParams() {
                Map<String, String> params = new HashMap<>();

                params.put("name", "Anupam");
                params.put("job", "Android Developer");


                return params;
            }

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<>();
                headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
                return headers;
            }

        };


        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("name", "JournalDev.com");
            jsonObject.put("job", "To teach you the best");
        } catch (JSONException e) {
            e.printStackTrace();
        }


        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(uri, jsonObject, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                VolleyLog.wtf(response.toString());
                Toast.makeText(getApplicationContext(), response.toString(), Toast.LENGTH_LONG).show();

            }
        }, errorListener) {

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

            @Override
            public Priority getPriority() {
                return Priority.NORMAL;
            }
        };


        StringRequest stringRequestPOSTJSON = new StringRequest(Request.Method.POST, uri, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                VolleyLog.wtf(response);
                Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();

            }
        }, errorListener) {
            @Override
            public Priority getPriority() {
                return Priority.HIGH;
            }

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<>();
                headers.put("Content-Type", "application/json; charset=utf-8");
                return headers;
            }

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

                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject.put("name", "Android Tutorials");
                    jsonObject.put("job", "To implement Volley in an Android Application.");
                } catch (JSONException e) {
                    e.printStackTrace();
                }

                String requestBody = jsonObject.toString();


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


        };

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


    }

    private void imageLoader() {
        RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();

        ImageLoader imageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {
            private final LruCache<String, Bitmap> mCache = new LruCache<>(10);

            public void putBitmap(String url, Bitmap bitmap) {
                mCache.put(url, bitmap);
            }

            public Bitmap getBitmap(String url) {
                return mCache.get(url);
            }
        });

        networkImageView.setImageUrl(IMAGE_URL, imageLoader);
        imageLoader.get(IMAGE_URL, ImageLoader.getImageListener(
                networkImageView, R.mipmap.ic_launcher, R.drawable.ic_error));
    }

    private void imageRequest() {
        RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();
        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, errorListener);

        mRequestQueue.add(imageRequest);
    }


    Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            if (error instanceof NetworkError) {
                Toast.makeText(getApplicationContext(), "No network available", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(getApplicationContext(), error.toString(), Toast.LENGTH_LONG).show();
            }
        }
    };

    private void customRequest() {
        mUserDataList.clear();
        RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();
        String url = String.format(BASE_URL + "/api/users?page=%1$s", "2");

        HashMap<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");

        GsonRequest<UserList> gsonRequest = new GsonRequest<>(url, UserList.class, headers, new Response.Listener<UserList>() {
            @Override
            public void onResponse(UserList response) {
                mUserDataList.addAll(response.userDataList);
                startActivity(new Intent(MainActivity.this, RecyclerViewActivity.class).putExtra("users", mUserDataList));

            }
        }, errorListener);

        mRequestQueue.add(gsonRequest);

    }

}

Android Volley Tutorial App in Action

The output of the android volley example application in action is given below.
android volley tutorial app

Download Android Volley Tutorial Project

This brings an end to android volley tutorial. You can download the Android Volley Project from the link below.

Comments

  1. Pranay Rangne says:

    {“imager”:[{“title”:”Guru”,”images”:[“images\/6.png”,”images\/androidIntro.png”,”images\/barretr_Earth.png”]}]}

    this is my JSON array how to fetch images from this array

  2. vivek says:

    Hi i want to be android developer . what technology i have to learn . what is hybride app also work like native .
    When to use native and hydride app development.

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