Volley cache Example

Volley cache Android is an HTTP library that makes networking for Android apps easier and most importantly, faster. Volley is available through the open AOSP repository. By default all the volley network calls works asynchronously, so we don’t have to worry about using asynctask anymore.

Features of Volley Android library

  • Automatic scheduling of network requests.
  • Multiple concurrent network connections.
  • Transparent disk and memory response caching with standard HTTP cache coherence.
  • Support for request prioritization.
  • Cancellation request API. You can cancel a single request, or you can set blocks or scopes of requests to cancel.
  • Ease of customization, for example, for retry and back off.
  • Strong ordering that makes it easy to correctly populate your UI with data fetched asynchronously from the network.
  • Debugging and tracing tools.

velmm download code

github

Please look into the presentation of Volley library at Google I/O


Related: Retrofit Android Example With Recyclerview [Download]


Create Project With Volley Android Library

Create new Project in Android Studio,

Open build.gradle and add volley support library,

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

Maintain volley core objects and request queue is, making them global by creating a singleton class which extends Application object.

public class AppController extends Application {

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

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized AppController getInstance() {
        return mInstance;
    }

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

    public ImageLoader getImageLoader() {
        getRequestQueue();
        if (mImageLoader == null) {
            mImageLoader = new ImageLoader(this.mRequestQueue,
                    new LruBitmapCache());
        }
        return this.mImageLoader;
    }

    public <T> void addToRequestQueue(Request<T> req, String tag) {
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }

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

    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

create a class named LruBitmapCache.java and paste the below code. This class is required to handle image cache.

public class LruBitmapCache extends LruCache<String, Bitmap> implements
        ImageLoader.ImageCache {
    public static int getDefaultLruCacheSize() {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;

        return cacheSize;
    }

    public LruBitmapCache() {
        this(getDefaultLruCacheSize());
    }

    public LruBitmapCache(int sizeInKiloBytes) {
        super(sizeInKiloBytes);
    }

    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }

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

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

Add the AppController.java into the Application tag in manifest.xml to execute this at app launch.and also add internet permission.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.velmurugan.volleycacheexample">
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <application
        android:name=".AppController"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
</manifest>

Now the setup is done. Below the methods, volley provides to make the HTTP requests.

Making JSON object request

Make a JSON object request where the JSON response will start with object notation ‘{

// Tag used to cancel the request
String tag_json_object = "json_obj_req";
String url = "http://35.200.174.74/apis/volley_object.json";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Method.GET,
        url, null,
        new Response.Listener<JSONObject>() {

            @Override
            public void onResponse(JSONObject response) {
                Log.d(TAG, response.toString());
            }
        }, new Response.ErrorListener() {

    @Override
    public void onErrorResponse(VolleyError error) {
        Log.d(TAG, error.toString());
    }
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsojsonObjectRequestnObjReq, tag_json_object);

Making JSON array request

Make JSON array request where the JSON response starts with array notation ‘[

// Tag used to cancel the request
String tag_json_arry = "json_array_request";
String url = "http://35.200.174.74/apis/volley_array.json";
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(url,
        new Response.Listener<JSONArray>() {
            @Override
            public void onResponse(JSONArray response) {
                Log.d(TAG, response.toString());
            }
        }, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        Log.d(TAG, error.toString());
    }
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonArrayRequest, tag_json_arry);

Making String request

StringRequest class will be used to fetch any kind of string data.

// Tag used to cancel the request
String  tag_string_request = "string_req";
String url = "http://35.200.174.74/apis/volley_array.json";
StringRequest stringRequest = new StringRequest(Method.GET,
        url, new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        Log.d(TAG, response.toString());
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        Log.d(TAG, error.toString());
    }
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(stringRequest, tag_string_request);

Making Post Request

To make POST request we have to override getParams() method which should return the list of parameters to send in a key-value format.

// Tag used to cancel the request
String tag_json_object = "json_obj_request";
String url = "http://35.200.174.74/apis/volley_array.json";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Method.POST,
        url, null,
        new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                Log.d(TAG, error.toString());
            }
        }, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        Log.d(TAG, response.toString());
    }
}) {
    @Override
    protected Map<String, String> getParams() {
        Map<String, String> params = new HashMap<String, String>();
        params.put("name", "Velmm.com");
        params.put("password", "*******");
        return params;
    }
};
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjectRequest, tag_json_object);

Request prioritization

Making multiple requests at the same time, you can prioritize the requests those you want to be executed first. The priory can be NormalLowImmediate and High.

private Priority priority = Priority.HIGH;
StringRequest strReq = new StringRequest(Method.GET,
        URL, new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        Log.d(TAG, response.toString());
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        VolleyLog.d(TAG, "Error: " + error.getMessage());
        hideProgressDialog();
    }
}) {
    @Override
    public Priority getPriority() {
        return priority;
    }
};

Making Image request

Volley introduced custom image view element called NetworkImageView to display the images from an URL. This will download images and maintain caches.

Loading image in NetworkImageView

ImageLoader imageLoader = AppController.getInstance().getImageLoader();
imgNetWorkView.setImageUrl(IMG_URL, imageLoader);

Loading image in ImageView

ImageLoader imageLoader = AppController.getInstance().getImageLoader();

imageLoader.get(movieList.get(position).getImageUrl(), new ImageLoader.ImageListener() {

    @Override
    public void onErrorResponse(VolleyError error) {

    }

    @Override
    public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
        holder.image.setImageBitmap(response.getBitmap());
    }
});

Adding placeholder image and error image

imageLoader.get(IMG_URL, ImageLoader.getImageListener(
        imageView, R.drawable.loading, R.drawable.error));

Adding the volley Cache

Volley comes with powerful cache mechanism to maintain request cache. This saves a lot of internet bandwidth and reduces user waiting time.

Loading request from cache

Cache cache = AppController.getInstance().getRequestQueue().getCache();
Cache.Entry entry = cache.get(jsonArrayUrl);
if(entry != null){

    try {
        String data = new String(entry.data ,"UTF-8");
        // Get JSON from the data 
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
} else {
    //Make network call 
}

Invalidate cache from volley

This method used to invalidate the cache of the API.That means when the changes added in the API response the cache will update to latest response.

AppController.getInstance().getRequestQueue().getCache().invalidate(url,true);

Turning off cache for volley

You can also turn off the cache for the particular API response using the following code.

// String request
StringRequest stringReq = new StringRequest(....);
// disable cache
stringReq.setShouldCache(false);

Cancel single request in volley

You can cancel the request using the tag name of the request.

String json_array_tag="tag_name";
AppController.getInstance().getRequestQueue().cancelAll("tag_name");

Cancel all request in volley

Use this code to cancel all the request.

AppController.getInstance().getRequestQueue().cancelAll();

Parsing JSON on Android using GSON

In your build.gradle you’ll need to add the dependencies for GSON

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

Define the Model

Use the SerializedName annotation when the property in the JSON does not exactly match the field of your class.

public class Movie {
    @SerializedName("title")
    private String title;
    @SerializedName("image")
    private String imageUrl;  
}

Create a new GSON instance in the onCreate method of our Activity.

    private Gson gson;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setDateFormat("M/d/yy hh:mm a");
        gson = gsonBuilder.create();
    }

This instance of GSON is what we’ll be using to parse the JSON response.

StringRequest strReq = new StringRequest(Request.Method.GET,
        jsonArrayUrl, new Response.Listener<String>() {

    @Override
    public void onResponse(String response) {
        Log.d(TAG, response.toString());
        movieList = Arrays.asList(gson.fromJson(response,Movie[].class));
    }
}, new Response.ErrorListener() {

    @Override
    public void onErrorResponse(VolleyError error) {
        Log.d(TAG, error.toString());
    }
});

Final MainActivity.java

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private RecyclerviewAdapter recyclerviewAdapter;
    private List<Movie> movieList;
    private String jsonArrayUrl="http://35.200.174.74/apis/volley_array.json";
    private Gson gson;
    private ProgressDialog pDialog;
    private String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setDateFormat("M/d/yy hh:mm a");
        gson = gsonBuilder.create();

        movieList = new ArrayList<>();
        recyclerView = (RecyclerView)findViewById(R.id.recyclerview);
        recyclerviewAdapter = new RecyclerviewAdapter();
        recyclerView.setAdapter(recyclerviewAdapter);

        pDialog = new ProgressDialog(this);
        pDialog.setMessage("Loading...");

        Cache cache = AppController.getInstance().getRequestQueue().getCache();
        Cache.Entry entry = cache.get(jsonArrayUrl);
        if(entry != null){

            try {
                String data = new String(entry.data ,"UTF-8");
                setData(data,true);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

        } else {
            callJsonArrayRequest();
        }
    }

    private void callJsonArrayRequest() {
        // TODO Auto-generated method stub
        showDialog();

        StringRequest strReq = new StringRequest(Request.Method.GET,
                jsonArrayUrl, new Response.Listener<String>() {

            @Override
            public void onResponse(String response) {
                Log.d(TAG, response.toString());
                setData(response,false);
                dismissDialog();
            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                dismissDialog();
            }
        });
        // Adding request to request queue
        AppController.getInstance().addToRequestQueue(strReq);
    }

    private void setData(String response,Boolean isCache){
        //Log.d(TAG, response.toString());
        movieList = Arrays.asList(gson.fromJson(response,Movie[].class));
        recyclerviewAdapter.setMovieList(movieList);
        if(isCache){
            Toast.makeText(getApplicationContext(), "Loading from Volley Cache", Toast.LENGTH_SHORT).show();
            dismissDialog();
        }
    }

    private void dismissDialog() {
        // TODO Auto-generated method stub
        if(pDialog.isShowing()){
            pDialog.dismiss();
        }
    }
    private void showDialog() {
        // TODO Auto-generated method stub
        if(!pDialog.isShowing()){
            pDialog.show();
        }
    }
}

Please try the example and let me know your feedback. You can download Example and Also can view example code in Github.

3 Responses

Leave a Reply

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

Back to Top