Android caching Volley + JSONObjectRequest

public class CustomRequest extends JsonObjectRequest { public CustomRequest(String url, JSONObject params, Listener<JSONObject> listener, ErrorListener errorListener) throws JSONException { super(Method.POST,url, params, listener, errorListener); this.setShouldCache(Boolean.TRUE); } } 

I was hoping that this piece of code would be enough so that I could get implicit response caching. I'm not sure if it works or not, because I was on an assumption when the request was sent:

  • he would hit the cache first and send it back

  • then when the results pass from the remote server, it will provide it onresponse

Update:

I figured out how to manually extract the cache and restore it to a JSONObject and send it through the OnResponse function, but this does not seem efficient, given that there is implicit caching. The JsonObjectRequest class should return a JSONObject as a cached record instead of the raw response data.

But I’m still interested to know if I’m not mistaken.

The ambiguity is explained only by the lack of documentation, so I apologize if I have something completely obvious.

+47
android caching android-volley response request
May 27 '13 at 10:18
source share
4 answers

See this answer - Set a cache expiration policy using Google Volley

This means that Volley decides whether to cache the response or not, based only on the "Cache-Control" headers, and then "Expires", "maxAge".

What you can do is change this com.android.volley.toolbox.HttpHeaderParser.parseCacheHeaders(NetworkResponse response) method and ignore these headers, set the entry.softTtl and entry.ttl for any value that suits you and use your method in its query class. Here is an example:

 /** * Extracts a {@link Cache.Entry} from a {@link NetworkResponse}. * Cache-control headers are ignored. SoftTtl == 3 mins, ttl == 24 hours. * @param response The network response to parse headers from * @return a cache entry for the given response, or null if the response is not cacheable. */ public static Cache.Entry parseIgnoreCacheHeaders(NetworkResponse response) { long now = System.currentTimeMillis(); Map<String, String> headers = response.headers; long serverDate = 0; String serverEtag = null; String headerValue; headerValue = headers.get("Date"); if (headerValue != null) { serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue); } serverEtag = headers.get("ETag"); final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely final long softExpire = now + cacheHitButRefreshed; final long ttl = now + cacheExpired; Cache.Entry entry = new Cache.Entry(); entry.data = response.data; entry.etag = serverEtag; entry.softTtl = softExpire; entry.ttl = ttl; entry.serverDate = serverDate; entry.responseHeaders = headers; return entry; } 

Use this method in your Request class as follows:

 public class MyRequest extends com.android.volley.Request<MyResponse> { ... @Override protected Response<MyResponse> parseNetworkResponse(NetworkResponse response) { String jsonString = new String(response.data); MyResponse MyResponse = gson.fromJson(jsonString, MyResponse.class); return Response.success(MyResponse, HttpHeaderParser.parseIgnoreCacheHeaders(response)); } } 
+85
May 31 '13 at 7:46
source share

oleksandr_yefremov provides excellent codes that can help you when working with the Android Volley cache strategy, especially when the REST API has incorrect "Cache-Control" headers or you just need to have more control over your own application cache strategy.

Key HttpHeaderParser.parseCacheHeaders(NetworkResponse response)) . If you want to have your own caching strategy. Replace it with parseIgnoreCacheHeaders(NetworkResponse response) in the appropriate class .

If your class extends JsonObjectRequest, go to JsonObjectRequest and find

 @Override protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) { try { String jsonString =new String(response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success(new JSONObject(jsonString),HttpHeaderParser.parseCacheHeaders(response)); }catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); }catch (JSONException je) { return Response.error(new ParseError(je)); } } 

and replace HttpHeaderParser.parseCacheHeaders(response) with HttpHeaderParser.parseIgnoreCacheHeaders

+5
Oct 11 '13 at 21:00
source share

+1 for oleksandr_yefremov and skyfishjy also offers here a specific 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 parseIgnoreCacheHeaders () function comes from the answer oleksandr_yefremov above. Use the CachingStringRequest class wherever the resulting json can cache for 3 minutes (live) and 24 hours (expired, but still available). Request example:

 CachingStringRequest stringRequest = new CachingStringRequest(MY_API_URL, callback); 

and inside the onResponse () callback function, parse json. Set any caching restrictions that you want — you can parameterize to add custom expiration per request.

For fun, try this in a simple application that downloads json and displays the downloaded information. After filling the cache with the first successful download, watch for fast rendering when you change orientation while the cache lives (loading does not take into account the hit in real time). Now kill the application, wait 3 minutes until its expiration date (but not 24 hours to remove it from the cache), turn on airplane mode and restart the application. A Volley error callback will be called, and the “successful” response to the onResponse () request will come from cached data, which will allow your application to both display the content and know / warn that it came from the expired cache.

One way to do this caching would be to eliminate boot loaders and other ways of handling orientation changes. If the request goes through Singleton Volley and the results are cached, updates that occur by changing the orientation are quickly displayed from the cache automatically using Volley without Loader.

Of course, this does not meet all the requirements. Ymmv

+2
Sep 18 '14 at 19:53
source share

I was able to force Volley to cache all responses by extending StringRequest and replacing the request that I want to force cache with CachingStringRequest .

In the overridden parseNetworkResponse method parseNetworkResponse I delete the Cache-Control headers. Thus, Volley stores the response in the built-in cache.

 public class CachingStringRequest extends StringRequest { private static final String CACHE_CONTROL = "Cache-Control"; public CachingStringRequest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener) { super(method, url, listener, errorListener); } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { // I do this to ignore "no-cache" headers // and use built-in cache from Volley. if (response.headers.containsKey(CACHE_CONTROL)) { response.headers.remove(CACHE_CONTROL); } return super.parseNetworkResponse(response); } } 
0
Aug 09 '17 at 9:00
source share



All Articles