首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HttpResponseCache不清除旧文件?

HttpResponseCache不清除旧文件?
EN

Stack Overflow用户
提问于 2014-05-19 15:22:54
回答 3查看 2K关注 0票数 1

我将很快完成一个项目,这个项目主要使用HTTPRequests来实现JSONImages,所以我认为考虑缓存是个好主意。基本上我在寻找一个解决方案

  1. 启动具有给定生存期的HTTPRequest (f.e。3,6,12小时)
  2. 检查该请求是否在缓存中可用,并且仍然有效(生存期)
  3. 如果请求仍然有效,则从缓存中提取它,否则发出请求并保存其响应。

我在安卓系统中找到了HttpResponseCache类。它正在工作,但是它是,而不是,正如我所期望的那样。

我的测试用例是一个缓存多个图像的AsyncTask。代码如下所示:

代码语言:javascript
复制
URL url = new URL(link);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

Bitmap myBitmap;
try {
    connection.addRequestProperty("Cache-Control","only-if-cached");

    //check if Request is in cache      
    InputStream cached = connection.getInputStream();

    //set image if in cache
    myBitmap = BitmapFactory.decodeStream(cached);

} catch (FileNotFoundException e) {
    HttpURLConnection connection2 = (HttpURLConnection) url.openConnection();
    connection2.setDoInput(true);
    connection2.addRequestProperty("Cache-Control", "max-stale=" + 60); 
    connection2.connect();

    InputStream input = connection2.getInputStream();
    myBitmap = BitmapFactory.decodeStream(input);

}

return myBitmap;

} catch (IOException e) {
    e.printStackTrace();        
}

两个问题:

  1. 我将max-stale=60seconds设置为测试目的。但是,如果我在5分钟后调用相同的URL,它会告诉我,它正在从缓存中加载图像。我会假设,因为缓存中的HTTPRequest过期了,所以图像被重新加载了?还是必须自己清理缓存?
  2. 在我的catch块中,我必须创建第二个HttpURLConnection,因为我在打开URLConnection之后不能添加属性(这发生在connection.getInputStream()?!)。这是糟糕的编程吗?

毕竟,我发现HttpResponseCache文档很少。我遇到了快速联网,但这似乎更少文档化,即使它提供了我所需要的东西(请求队列和优先级.)。您用来缓存什么?欢迎访问库、教程的链接。

更新--我的目标不是低于4.0的安卓版本(可能还在为其他用户提供更多?)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-05-29 06:16:05

HttpResponseCachevolley的文档都不多。但是,我发现您可以很容易地扩展和调整volley。如果您研究volley的源代码,特别是:CacheEntryCacheDispatcherHttpHeaderParser的源代码,您可以看到它是如何实现的。

CacheEntry包含serverDateetagttlsofTtl,它们可以很好地表示缓存状态,同时还具有isExpired()refreshNeeded()方法。

CacheDispatcher的实现也是准确的:

代码语言:javascript
复制
// Attempt to retrieve this item from cache.
Cache.Entry entry = mCache.get(request.getCacheKey());

if (entry == null) {
    request.addMarker("cache-miss");
    // Cache miss; send off to the network dispatcher.
    mNetworkQueue.put(request);
    continue;
}

// If it is completely expired, just send it to the network.
if (entry.isExpired()) {
    request.addMarker("cache-hit-expired");
    request.setCacheEntry(entry);
    mNetworkQueue.put(request);
    continue;
}

// We have a cache hit; parse its data for delivery back to the request.
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
        new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");

if (!entry.refreshNeeded()) {
    // Completely unexpired cache hit. Just deliver the response.
    mDelivery.postResponse(request, response);
} else {
    // Soft-expired cache hit. We can deliver the cached response,
    // but we need to also send the request to the network for
    // refreshing.
    request.addMarker("cache-hit-refresh-needed");
    request.setCacheEntry(entry);

    // Mark the response as intermediate.
    response.intermediate = true;

    // Post the intermediate response back to the user and have
    // the delivery then forward the request along to the network.
    mDelivery.postResponse(request, response, new Runnable() {
        @Override
        public void run() {
            try {
                mNetworkQueue.put(request);
            } catch (InterruptedException e) {
                // Not much we can do about this.
            }
        }
    });
}

一个有趣的小贴士:如果缓存是“软过期”,volley将立即从本地缓存传递数据,并在一段时间后从服务器重新发送数据,用于单个请求。

最后,HttpHeaderParser尽力处理服务器头:

代码语言:javascript
复制
headerValue = headers.get("Date");
if (headerValue != null) {
    serverDate = parseDateAsEpoch(headerValue);
}

headerValue = headers.get("Cache-Control");
if (headerValue != null) {
    hasCacheControl = true;
    String[] tokens = headerValue.split(",");
    for (int i = 0; i < tokens.length; i++) {
        String token = tokens[i].trim();
        if (token.equals("no-cache") || token.equals("no-store")) {
            return null;
        } else if (token.startsWith("max-age=")) {
            try {
                maxAge = Long.parseLong(token.substring(8));
            } catch (Exception e) {
            }
        } else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {
            maxAge = 0;
        }
    }
}

headerValue = headers.get("Expires");
if (headerValue != null) {
    serverExpires = parseDateAsEpoch(headerValue);
}

serverEtag = headers.get("ETag");

// Cache-Control takes precedence over an Expires header, even if both exist and Expires
// is more restrictive.
if (hasCacheControl) {
    softExpire = now + maxAge * 1000;
} else if (serverDate > 0 && serverExpires >= serverDate) {
    // Default semantic for Expire header in HTTP specification is softExpire.
    softExpire = now + (serverExpires - serverDate);
}

Cache.Entry entry = new Cache.Entry();
entry.data = response.data;
entry.etag = serverEtag;
entry.softTtl = softExpire;
entry.ttl = entry.softTtl;
entry.serverDate = serverDate;
entry.responseHeaders = headers;

因此,确保服务器发送正确的头部以及荣誉etag,时间戳和缓存控制报头.

最后,您可以重写getCacheEntry() of Request类来返回自定义CacheEntry使缓存完全按照您的需要运行。

票数 2
EN

Stack Overflow用户

发布于 2014-05-28 22:33:38

对不起。但你为什么不用第三方语言呢?为此尝试使用截击库。它维护一个开箱即用的缓存,并且它是从盒子中异步出来的。效果真的很好。截击教程:一个(带有缓存演示)

还有另一种很好的异步方式,就是用良好的文档为android缓存库-- 改造。这是改造缓存示例

这里是他们的比较。

票数 2
EN

Stack Overflow用户

发布于 2014-05-23 04:28:40

要启用缓存,只需使用以下代码在应用程序启动时安装HTTP响应缓存:

代码语言:javascript
复制
File httpCacheDir = new File(context.getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);

是否需要从网络或缓存中获取资源,由HttpResponseCache来处理。缓存的年龄在资源请求的响应头中指定。例如,此图像指定缓存时间为43200秒。

通过使用以下apis,可以验证资源是从缓存还是从网络中获取的:

  • getHitCount:缓存服务的Http请求的数量。
  • getNetworkCount:由网络服务的Http请求的数量。

关于max-stale,您误解了它的目的。它用于允许过时的缓存响应。以下是来自rfc文档的定义:

指示客户端愿意接受超过其过期时间的响应。如果为max-stale分配了一个值,则客户端愿意接受超过其过期时间不超过指定秒数的响应。如果不给最大值赋值,则客户愿意接受任何年龄的陈腐响应。

关于缓存控制指令only-if-cached,仅在应用程序下载最新内容时需要显示某些内容时才使用它。因此,在异常处理程序中处理新HttpUrlConnection的问题不会出现。来自文档

有时,如果资源是立即可用的,则需要显示它们,而不是其他资源。这样您的应用程序就可以在等待下载最新数据时显示一些内容。若要将请求限制为本地缓存的资源,请添加唯一的if缓存指令。

一个建议是添加finally块,在这里通过调用断开连接释放连接。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23741528

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档