2013-05-27 60 views
48
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); 
    } 
} 

我希望这段代码足以让我隐式缓存响应。我不知道是否可行与否,因为我的假设下,当发送一个请求:Android Volley + JSONObjectRequest缓存

  1. 那就先打缓存并发送至onresponse

  2. 那么当结果从远程服务器通过它来将其提供给onresponse

更新:

我想通了如何手动检索缓存和重建它,我nto JSONObject并通过OnResponse函数发送它,但考虑到存在隐式缓存,这看起来效率不高。 JsonObjectRequest类应该返回JSONObject作为缓存条目而不是原始响应数据。

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

模棱两可仅仅是由于缺乏文档,所以我很抱歉如果我失去了一些非常明显的东西。

回答

86

看到这个答案 - Set expiration policy for cache using Google's Volley

这意味着凌空决定仅仅基于头“缓存控制”,然后“过期”,“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; 
} 

使用此方法在你的请求类是这样的:

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

} 
+1

这是否意味着缓存将超越,onDestroy?所以下次创建应用程序时,它会从缓存中获取? – gaara87

+3

是的,缓存不仅保存在内存中,还保存在磁盘上(详情请参阅DiskBasedCache类)。作为一个快速测试,加载一些数据,退出你的应用程序,关闭WiFi或3G,然后再次输入你的应用程序。您还可以在mMaxCacheSizeInBytes字段中指定缓存大小。 –

+2

是的,它在我进入应用程序时缓存,但当我退出应用程序并返回到应用程序时,从缓存中获取返回null。因此,它是否存在于活动生命周期之间。 – gaara87

5

oleksandr_yefremov提供了极大的代码可以帮助你,当你处理的Android凌空缓存策略,尤其是当REST API具有不正确的“缓存控制”标题,或者您只是想要更多地控制自己的应用程序缓存策略。

关键是HttpHeaderParser.parseCacheHeaders(NetworkResponse response))。如果你想拥有自己的缓存策略。用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.parseIgnoreCacheHeaders

+0

是否有可能通过'NetworkImageView'做到这一点? – fiddler

2

+1 oleksandr_yefremov和skyfishjy同时更换HttpHeaderParser.parseCacheHeaders(response),这里提供一个具体的,可重用的类适用于JSON或其他基于字符串的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()com es从上面的oleksandr_yefremov答案中获得。在生成的json可以缓存3分钟(活动)和24小时(过期但仍然可用)的任何地方使用CachingStringRequest类。样品请求:

CachingStringRequest stringRequest = new CachingStringRequest(MY_API_URL, callback); 

和回调对象的onResponse()函数中,解析JSON。设置你想要的任何缓存限制 - 你可以参数化来为每个请求添加自定义到期。

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

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

当然,这不符合所有要求。 YMMV

0

我能够迫使Volley通过扩展StringRequest来缓存所有响应,并用CachingStringRequest取代了我想强制缓存的请求。

覆盖的方法parseNetworkResponse我删除了Cache-Control标头。通过这种方式,Volley正在将响应持久保存在内置缓存中。

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); 
    } 
} 
相关问题