Android Development #5: Using Volley and GSON

First posted on 11/02/2014

What is GSON

Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of. (Source)

What is Volley

Volley is a library that makes networking for Android apps easier and most importantly, faster.
It manages the processing and caching of network requests and it saves developers valuable time from writing the same network call/cache code again and again. And one more benefit of having less code is less number of bugs and that’s all developers want and aim for. (Source)

Combine them together, then we have a perfect package for our network calls!

Let's start using it. Firstly, import both libraries into your project.

Then, create a class that will serve both libraries as a utility. We name it GsonRequest.

/**
 * Copyright 2013 Ognyan Bankov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

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.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;

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

/**
 * Volley adapter for JSON requests with POST method that will be parsed into Java objects by Gson.
 */
public class GsonRequest<T> extends Request<T> {
    private Gson mGson = new Gson();
    private Class<T> clazz;
    private Map<String, String> headers;
    private Map<String, String> params;
    private Listener<T> listener;

    /**
     * Make a GET request and return a parsed object from JSON.
     *
     * @param url URL of the request to make
     * @param clazz Relevant class object, for Gson's reflection
     */
    public GsonRequest(int method,
                       String url,
                       Class<T> clazz,
                       Listener<T> listener,
                       ErrorListener errorListener) {
        super(method, url, errorListener);
        this.clazz = clazz;
        this.listener = listener;
        mGson = new Gson();
    }

    /**
     * Make a POST request and return a parsed object from JSON.
     *
     * @param url URL of the request to make
     * @param clazz Relevant class object, for Gson's reflection
     */
    public GsonRequest(int method,
                       String url,
                       Class<T> clazz,
                       Map<String, String> params,
                       Listener<T> listener,
                       ErrorListener errorListener) {

        super(method, url, errorListener);
        this.clazz = clazz;
        this.params = params;
        this.listener = listener;
        this.headers = null;
        mGson = new Gson();
    }

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

    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        return params;
    }

    @Override
    protected void deliverResponse(T response) {
        listener.onResponse(response);
    }

    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response) {
        try {
            String json = new String(
                    response.data, HttpHeaderParser.parseCharset(response.headers));
            return Response.success(
                    mGson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JsonSyntaxException e) {
            return Response.error(new ParseError(e));
        }
    }
}

Usage

GET Method

    private void loadAPI() {
        mRequestQueue = Volley.newRequestQueue(getActivity());

        String url = "http://www.example.com/api/photos/";

        GsonRequest<ModelContainer> myReq = new GsonRequest<ModelContainer>(
                Request.Method.GET,
                url,
                ModelContainer.class,
                createMyReqSuccessListener(),
                createMyReqErrorListener());

        mRequestQueue.add(myReq);
    }

    private Response.Listener<ModelContainer> createMyReqSuccessListener() {
        return new Response.Listener<ModelContainer>() {
            @Override
            public void onResponse(ModelContainer response) {
                try {
                 Log.d("Json Response", response.toString);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
        };
    }

    private Response.ErrorListener createMyReqErrorListener() {
        return new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                String errorMsg = VolleyErrorHelper.getMessage(error, getActivity());

                Toast.makeText(getActivity(), errorMsg, Toast.LENGTH_LONG)
                        .show();
            }
        };
    }

POST Method

You only have to add the param and pass it into the params.

    private void loadAPI(){
        String url = http://www.example.com/api/login/;

        // Create parameters
        SessionManager session = new SessionManager(getActivity());
        HashMap<String, String> params = session.getUserDetails();
        params.put("somekey", "somevalue");

        mRequestQueue = Volley.newRequestQueue(getActivity());

        // Request with API parameters
        GsonRequest<ModelContainer> myReq = new GsonRequest<ModelContainer>(
                com.android.volley.Request.Method.POST,
                url,
                ModelContainer.class,
                params,
                createMyReqSuccessListener(),
                createMyReqErrorListener());


        mRequestQueue.add(myReq);
    }

Request custom header for authorization:

 private void loadAPI(){
        String url = http://www.example.com/api/login/;

        // Create parameters
        SessionManager session = new SessionManager(getActivity());
        HashMap<String, String> params = session.getUserDetails();
        params.put("somekey", "somevalue");

        mRequestQueue = Volley.newRequestQueue(getActivity());

        // Request with API parameters
        GsonRequest<ModelContainer> myReq = new GsonRequest<ModelContainer>(
                com.android.volley.Request.Method.POST,
                url,
                ModelContainer.class,
                params,
                createMyReqSuccessListener(),
                createMyReqErrorListener()) {

                    @Override
                    public Map<String, String> getHeaders() throws AuthFailureError {

                        HashMap<String, String> headers = new HashMap<String, String>();
                        headers.put("user-agent", "some_bitch_ass_header");

                        return headers;
                    }
                };


        mRequestQueue.add(myReq);
    }

Get JSON response:


    private void loadAPI(){
        String url = http://www.example.com/api/login/;

        // Create parameters
        SessionManager session = new SessionManager(getActivity());
        HashMap<String, String> params = session.getUserDetails();
        params.put("somekey", "somevalue");

        mRequestQueue = Volley.newRequestQueue(getActivity());

        // Request with API parameters
        GsonRequest<ModelContainer> myReq = new GsonRequest<ModelContainer>(
                com.android.volley.Request.Method.POST,
                url,
                ModelContainer.class,
                params,
                createMyReqSuccessListener(),
                createMyReqErrorListener()) {
                    @Override
                    protected void deliverResponse(HomeContainer response) {

                        Log.d(TAG, "deliverResponse= "+response.toString());

                        super.deliverResponse(response);
                    }
                };


        mRequestQueue.add(myReq);
    }

Model Class (POJO)

Say for example our JSON was formatted as follow:

{
  "results": {
    "user_id": "99401",
    "username": "aimanbaharum",
    "name": "Aiman Baharum",
    "profile": [
      {
        "id": "1",
        "title": "You w0t m8",
        "content": null
      },
      {
        "id": "2",
        "title": "Top lel",
        "content": "some values"
      }, ...
    ],
    "items": [
      ...
    ]
  },
  "errors": ""
}

As we can see in the above JSON, it has an Object as the root. Inside the Object, contains some Children.

To make it more understandable, we define it as follows:

(Object) Root
 - results
  -- user_id
  -- username
  -- name
  -- (Array) profile
   --- id
   --- title
   --- content
  -- (Array) items
 - errors

So, let's start creating the POJOs to mirror our JSON. The first model that we have to create is the Container which holds the Root object.

Note: There might be another way to do this, but this is what I always did.

ModelContainer.java


// root
public class ModelContainer {
 ClassModel results;
 String errors;

 // create Constructor, Getter/Setter, toString
}

ClassModel.java


// children of root
public class ClassModel {
 String user_id;

 @SerializedName("username")
 String user_fucking_name;
 String name;
 ArrayList<ProfileModel> profile;
 ArrayList<ItemModel> items;

 // create constructor, getter/setter, toString
}

ProfileModel.java


// children of ClassModel
public class ProfileModel {
 String id;
 String title;
 String content;

 // create constructor, getter/setter, tostring
}

Notice the @SerializedName annotation in ClassModel? Use this when you need to assign a different name in your variable instead of using the same key name in JSON.

If it is an Array, use ArrayList to model the JSON.

How to traverse between those models?

Make sure you have set the Setter and Getter properly in its model. To traverse between the models, use the response to get all the values that has been parsed by Gson and Volley.

Example, get the username:
String username = response.getResults().getUser_fucking_name();

To loop between arrays or objects, below code demonstrates on how to get all the Profile arrays data:

for (int i = 0; i < response.getResults().getProfile().size(); i++) {
 ProfileModel pm = new ProfileModel();
 Log.d("Profile Model response", pm.getTitle());
}
Show Comments

Get the latest posts delivered right to your inbox.