Tag Archives: Volley JSON Request

Volley PART I

Hello Guys,
I have been working on different projects and got a very nice experience of using volley.
Although Retrofit is also much efficient, but as Volley provides Caching, Cancelling of request, Cancel of  multiple image request if view or UI is not available and which actually fascinates me to use Volley.

And in this blog I am going to share my code for hitting JSON request (JSON object and JSON array both),String response request, Image upload, Image download, Use of Network Image View which is also much efficient (provided by volley only) and also to have Rounded Network Image View which I have used in few screens.
And for all this I have made base (custom) classes, so that anyone can easily use it and directly integrate in their project.
Now first of all to use Volley, you need to add Volley dependency in build.gradle.

Starting from basic :

1) Make one Project, Goto File -> New Project.

2) Then go in Project Folder -> app -> build.gradle.
Add 
compile ‘com.mcxiaoke.volley:library-aar:1.0.0’ in dependencies {}.

3) Now we are creating a base class for creating volley request object.
We are making this a singleton class, as we require only a single object for requesting throughout application.
Also we are creating object “Image Loader” which is responsible of downloading images, which we are going to use further in our example.
Image Loader uses LRUCache.
And another object of “Request Queue”, which will keep all request in queue and call it based on Priority.

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import android.text.TextUtils;

import com.android.volley.Cache;
import com.android.volley.Network;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.BasicNetwork;
import com.android.volley.toolbox.DiskBasedCache;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.ImageLoader;

/**
 * Created by sunny on 8/12/15.
 */
public class MyVolley {

    private static MyVolley mInstance;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private static Context mCtx;
    public static final String TAG = MyVolley.class.getSimpleName();

    private MyVolley(Context context) {
        mCtx = context;
        mRequestQueue = getRequestQueue();

        mImageLoader = new ImageLoader(mRequestQueue,
                new ImageLoader.ImageCache() {
                    private final LruCache<String, Bitmap>
                            cache = new LruCache<String, Bitmap>(20);

                    @Override
                    public Bitmap getBitmap(String url) {
                        return cache.get(url);
                    }

                    @Override
                    public void putBitmap(String url, Bitmap bitmap) {
                        cache.put(url, bitmap);
                    }
                });

        //Added to make image upload and download faster!
        //mImageLoader.setBatchedResponseDelay(0);
    }

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

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            // getApplicationContext() is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            Cache cache = new DiskBasedCache(mCtx.getCacheDir(), 10 * 1024 * 1024);
            Network network = new BasicNetwork(new HurlStack());

// We can give Thread Pool Size
 mRequestQueue = new RequestQueue(cache, network,10);

 // Don't forget to start the volley request queue
 mRequestQueue.start();
 //mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
 }
 return mRequestQueue;
 }

 public <T> void addToRequestQueue(Request<T> req) {
 getRequestQueue().add(req);
 }

 public <T> void addToRequestQueue(Request<T> req, String tag) {
 // set the default tag if tag is empty
 req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
 getRequestQueue().add(req);
 }

 public ImageLoader getImageLoader() {
 return mImageLoader;
 }


}

Now we are creating one generic class for JSON requests (JSON array and JSON object both), please note that I have used GSON for parsing json object.
So first add latest version of Gson in build.gradle.

compile 'com.google.code.gson:gson:2.5'

GSONRequest Class :

import android.app.ProgressDialog;
import android.content.Context;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
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 com.example.utility.dialog.ProgressBarDialog;
import com.example.utility.logs.Logcat;

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

/**
 * Created by sunny on 8/12/15.
 */
public class GsonRequest<T> extends Request<T> {
    private final Gson gson = new Gson();
    private final Class<T> clazz;
    private Map<String, String> headers;
    private final Response.Listener<T> listener;
    private final Context ctxt;
    private final Map<String, String> params;
    public static final String TAG = GsonRequest.class.getSimpleName();

    //Adding CustomErrorListener, so that we will not be required to mention in all activities!
    private CustomErrorListener customErrorListener;
    private ProgressBarDialog progressBarDialog;

    private ProgressDialog progressDialog;

    /**
     * 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
     * @param headers Map of request headers
     */
    public GsonRequest(String url, Class<T> clazz, Map<String, String> headers,
                       Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> params, Context ctxt, int methodType, boolean showDialog) {
        super(methodType, url, errorListener);
        setRetryPolicy(new DefaultRetryPolicy(VolleyUtils.DEFAULT_TIMEOUT_MS,
                VolleyUtils.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

        this.clazz = clazz;
        this.headers = headers;
        this.listener = listener;
        this.params = params;
        this.ctxt = ctxt;
        customErrorListener = (CustomErrorListener) errorListener;


        if (showDialog == true) {
            showProgressDialog();
        }

    }

      public void showProgressBarDialog() {
        if (progressBarDialog == null) {
            progressBarDialog = ProgressBarDialog.getInstance(ctxt);

            if (null != customErrorListener) {
                //customErrorListener.setProgressBarDialog(progressBarDialog);
            }
        }
        progressBarDialog.showProgressDialog();
    }


    public void closeProgressDialog() {
        if (null != progressBarDialog && progressBarDialog.isShowing()) {
            progressBarDialog.dismissDialog();
        }
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        if (headers != null) {
            return headers;
        } else {
            headers = VolleyGlobal.getInstance(ctxt).getHeaders();
            Logcat.showLog(TAG, headers.values().toString());
            return headers;
        }

    }


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


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

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


    public void showProgressDialog() {
        progressDialog = ProgressDialog.show(ctxt, "Please wait", "Processing...", true, false);
        customErrorListener.setProgressBarDialog(progressDialog);
    }

    public void dismissProgressDialog() {
        if (null != progressDialog) {
            progressDialog.dismiss();
        }
    }

}

 

In the above class we have used constructor to pass data and initialize object, also we have have used boolean to show dialog or not.

VolleyGlobal Class :

import android.content.Context;

import com.android.volley.AuthFailureError;
import com.example.utility.Constants;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by sunny on 8/12/15.
 */
public class VolleyGlobal {

    private static VolleyGlobal mInstance;
    private static Context mCtx;
    public static final String TAG = VolleyGlobal.class.getSimpleName();
    private static HashMap<String, String> headers = new HashMap<String, String>();

    private VolleyGlobal(Context context) {
        mCtx = context;
    }


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

    public Map<String, String> getHeaders() throws AuthFailureError {
        //headers.put("Content-Type", "application/json");
        return headers;
    }

  }


This class will keep header parameters if required (like access token, api key or user id, etc.) any for your application.

 

I) Example of simple JSON request :

Now we will create one UI for hitting the simple JSON request. I have made one screen for changing password, which will hit a background call. This screen consists of 3 edittext that is, old password, new password and confirm password, and one save button.

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

import com.android.volley.Request;
import com.android.volley.Response;
import com.example.R;
import com.example.custom.activities.BaseAppCompactActivity;
import com.example.pojo.login.BasicPojo;
import com.example.utility.Constants;
import com.example.utility.Utils;
import com.example.volley.CustomErrorListener;
import com.example.volley.GsonRequest;
import com.example.volley.MyVolley;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by sunny on 3/12/15.
 */
public class ChangePwdActivity extends BaseAppCompactActivity implements View.OnClickListener, Response.Listener {

    private Toolbar toolbar;
    private TextView txtSave;
    private EditText editOldPwd, editNewPwd, editConfirmPwd;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_change_password);
        toolbar = (Toolbar) findViewById(R.id.toolbar);

        toolbar.setTitle(R.string.change_password);

        toolbar.setNavigationIcon(R.drawable.header_icon_back);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });

        txtSave = (TextView) findViewById(R.id.txtSave);
        txtSave.setOnClickListener(this);

        editOldPwd = (EditText) findViewById(R.id.editOldPwd);
        editNewPwd = (EditText) findViewById(R.id.editNewPwd);
        editConfirmPwd = (EditText) findViewById(R.id.editConfirmPwd);

    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.txtSave) {
            callChangePwdReq();
        }
    }

    public boolean validateFields() {
        String pwd = new String(editNewPwd.getText().toString().trim());
        String confPwd = new String(editConfirmPwd.getText().toString().trim());
        if (TextUtils.isEmpty(pwd)) {
            Utils.makeShortToast(this, getString(R.string.please_enter_pwd));
            return false;
        } else if (TextUtils.isEmpty(confPwd)) {
            Utils.makeShortToast(this, getString(R.string.please_enter_confirm_pwd));
            return false;
        } else if (pwd.length() < getResources().getInteger(R.integer.password_minimum_length)) {
            Utils.makeShortToast(this, getResources().getString(R.string.please_enter_pwd_six_characters));
            return false;
        } else if (!pwd.equals(confPwd)) {
            Utils.makeShortToast(this, getString(R.string.your_pwd_confpwd_not_match));
            return false;
        }
        return true;
    }


    public void callChangePwdReq() {
        if (validateFields()) {
            String url = Constants.SERVER_URL + "user/change_password";
            String tag_chng_pwd_req = "change_pwd";


            Map<String, String> params = new HashMap<String, String>();
            params.put("old_password", Utils.checkForNullValue(editOldPwd.getText().toString().trim()));
            params.put("new_password", Utils.checkForNullValue(editNewPwd.getText().toString().trim()));

            CustomErrorListener customErrorListener = new CustomErrorListener(ChangePasswordActivity.this);
            GsonRequest gsonRequest = new GsonRequest(url, BasicPojo.class, null, this, customErrorListener, params, this, Request.Method.POST, true);
           MyVolley.getInstance(getApplicationContext()).addToRequestQueue(gsonRequest, tag_chng_pwd_req);
        }
    }

    
    @Override
    public void onResponse(Object response) {
        if (response instanceof BasicPojo) {
            BasicPojo pwdPojo = (BasicPojo) response;
//If requests gets success!
            if (Integer.valueOf(pwdPojo.getSuccess()) == Constants.REQUEST_HIT_SUCCESS) {
                Utils.makeShortToast(this, pwdPojo.getMessage());
                finish();
            } else {
//Else if we get failure from server.
                Utils.makeShortToast(this, pwdPojo.getMessage());
            }
        }
    }
}

As volley has two listeners that is, ErrorListener and Response.Listener (for Success of request).

We have made our own custom error listener so that it can be used at multiple activities and also to handle multiple types of error at one place only.

CustomErrorListener:

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import com.android.volley.AuthFailureError;
import com.android.volley.NetworkError;
import com.android.volley.NoConnectionError;
import com.android.volley.ParseError;
import com.android.volley.ServerError;
import com.android.volley.TimeoutError;
import com.android.volley.VolleyError;
import com.android.volley.Response.ErrorListener;
import com.example.pojo.login.BasicPojo;
import com.example.utility.Utils;
import com.example.utility.logs.Logcat;
import com.example.volley.VolleyGlobal;

public class CustomErrorListener implements ErrorListener {
    private Context context;
    private ProgressDialog progressBarDialog;
    private final String TAG = CustomErrorListener.class.getSimpleName();

    public CustomErrorListener(Context context) {
        this.context = context;
    }

    public void setProgressBarDialog(ProgressDialog progressBarDialog) {
        this.progressBarDialog = progressBarDialog;
    }

    public void onErrorResponse(VolleyError error) {
        if(null != this.progressBarDialog && this.progressBarDialog.isShowing()) {
            this.progressBarDialog.dismiss();
        }

        if(null == error.getMessage()) {
            Logcat.showLog(this.TAG, error.getClass().toString());
        } else {
            Logcat.showLog(this.TAG, error.getMessage());
        }

        String errorText = null;
        if(error instanceof BasicPojo) {
            errorText = error.getMessage();
        } else if(error instanceof ServerError) {
            errorText = "ServerError";
        } else if(error instanceof AuthFailureError) {
            errorText = "AuthFailureError";
        } else if(error instanceof ParseError) {
            errorText = "ParseError";
        } else if(error instanceof NoConnectionError) {
            String msg = error.getCause().getMessage();
            if(msg.equalsIgnoreCase("No Authentication challenges found")) {
                errorText = this.context.getString(2131099844);
                this.callLoginScreen();
            } else {
                errorText = this.context.getString(2131099820);
            }
        } else if(error instanceof TimeoutError) {
            errorText = this.context.getString(2131099740);
        } else if(error instanceof NetworkError) {
            errorText = this.context.getResources().getString(2131099813);
        }

        if(null != errorText) {
            Utils.makeShortToast(this.context, errorText);
        } else {
            Utils.makeShortToast(this.context, this.context.getString(2131099813));
        }

    }

}

Basic Pojo (which consists of success flag and message), It can be different in your case :

import com.android.volley.VolleyError;

public class BasicPojo extends VolleyError {
    private String message;
    private String success;

    public BasicPojo() {
    }

    public String getMessage() {
        return this.message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getSuccess() {
        return this.success;
    }

    public void setSuccess(String success) {
        this.success = success;
    }
}



Next part will consists of image uploading (with data and without data), with integrating image cropping library, and downloading of image. (Volley PART II)