+1 for oleksandr_yefremov and skyfishjy also, and offering here a concrete, reusable class suitable for json or other string-based APIs:
public class CachingStringRequest extends StringRequest {
public CachingStringRequest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
super(method, url, listener, errorListener);
}
public CachingStringRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
super(url, listener, errorListener);
}
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed, parseIgnoreCacheHeaders(response));
}
}
where the function parseIgnoreCacheHeaders() comes from the oleksandr_yefremov answer above. Use the CachingStringRequest class anywhere that the resulting json is ok to cache for 3 minutes (live) and 24 hours (expired but still available). A sample request:
CachingStringRequest stringRequest = new CachingStringRequest(MY_API_URL, callback);
and within the callback object's onResponse() function, parse the json. Set whatever caching limits you want--you could parameterize to add custom expiration per request.
For fun, try this in a simple app that downloads json and renders the downloaded info. Having filled the cache with the first successful download, watch the speedy rendering as you change orientations while cache is live (no download occurs given a live cache hit). Now kill the app, wait 3 minutes for that cache hit to expire (but not 24 hours for it to be removed from cache), enable airplane mode, and restart the app. The Volley error callback will occur, AND the "successful" onResponse() callback will occur from cached data, allowing your app to both render content and also know/warn that it came from expired cache.
One use of this kind of caching would be to obviate Loaders and other means of dealing with orientation change. If a request goes through a Volley singleton, and results are cached, refreshes that happen via orientation change are rendered quickly from cache, automatically by Volley, without the Loader.
Of course, this doesn't fit all requirements. YMMV