Android Volley + JSONObjectRequestcaching

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); } } 

我希望这段代码足以让我隐式caching响应。 我不确定它是否有效,因为我是在发送请求时的假设下:

  1. 它会先打高速caching,然后发送回应

  2. 那么当结果通过远程服务器时,它会将其提供给响应者

更新:

我想如何手动检索caching并将其重构为JSONObject并通过OnResponse函数发送,但考虑到存在隐式caching,这似乎并不高效。 JsonObjectRequest类应该返回JSONObject作为caching项而不是原始响应数据。

但是我仍然有兴趣知道我是否犯了一些错误。

含糊不清只是由于缺乏文件,所以我很抱歉,如果我失去了一些相当明显的东西。

看到这个答案 – 使用Google的Volley设置caching的到期策略

这意味着Volley决定是否caching响应,而不是仅基于头“caching控制”,然后“过期”,“maxAge”。

你可以做的是改变这个方法com.android.volley.toolbox.HttpHeaderParser.parseCacheHeaders(NetworkResponse response)并忽略这些头,设置entry.softTtlentry.ttl字段为您适用的任何值,并在您的请求中使用您的方法类。 这里是一个例子:

 /** * 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; } 

在你的Request类中使用这个方法是这样的:

 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)); } } 

oleksandr_yefremov提供了很棒的代码,可以帮助你处理Android Volley的caching策略,特别是当REST API有不正确的“caching控制”头时,或者你只是想要更多地控制自己的应用caching策略时。

关键是HttpHeaderParser.parseCacheHeaders(NetworkResponse response)) 。 如果你想拥有自己的caching策略。 将其replace为相应类中的 parseIgnoreCacheHeaders(NetworkResponse response)

如果您的类扩展了JsonObjectRequest,请转到JsonObjectRequest并查找

 @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)); } } 

并用HttpHeaderParser.parseCacheHeaders(response)replaceHttpHeaderParser.parseCacheHeaders(response)

也为oleksandr_yefremov和skyfishjy +1,并在这里提供一个具体的,可重用的类适用于JSON或其他基于string的API:

 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)); } } 

函数parseIgnoreCacheHeaders()来自上面的oleksandr_yefremov答案。 使用CachingStringRequest类,可以将生成的jsoncaching3分钟(实时)和24小时(过期但仍然可用)。 示例请求:

 CachingStringRequest stringRequest = new CachingStringRequest(MY_API_URL, callback); 

并在callback对象的onResponse()函数中parsingjson。 设置你想要的任何caching限制 – 你可以参数化为每个请求添加自定义到期。

为了好玩,试试这个简单的应用程序下载json并呈现下载的信息。 在第一次成功下载之后填充caching,在caching生效的同时更改方向,观看快速渲染(由于实时caching命中,不会下载)。 现在杀死应用程序,等待3分钟,caching命中过期(但不是24小时,它从caching中删除),启用飞行模式,并重新启动应用程序。 Volley错误callback将发生,并且“成功”的onResponse()callback将从caching数据中发生,允许您的应用程序同时呈现内容并且还知道/警告它来自过期caching。

这种caching的一个用途是避免装载机和其他处理方向改变的手段。 如果一个请求通过一个Volley单例,并且结果被caching,那么通过方向改变发生的刷新将从caching中快速呈现,由Volley自动完成,不需要Loader。

当然,这不符合所有要求。 因人而异

我能够迫使Volley通过扩展StringRequest来caching所有的响应,并replace我想用CachingStringRequest强制caching的CachingStringRequest

在重写的方法parseNetworkResponse我删除Cache-Control头。 这样Volley正在将响应保存在内置的caching中。

 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); } }