gpt4 book ai didi

android - HttpResponseCache 不清除旧文件?

转载 作者:行者123 更新时间:2023-11-29 15:16:16 25 4
gpt4 key购买 nike

我很快将在一个项目上工作,该项目使用大量 HTTPRequests 主要用于 JSONImages,所以我认为它是考虑缓存是个好主意。基本上我正在寻找

的解决方案
  1. 启动具有给定生命周期(例如 3、6、12 小时)的 HTTPRequest
  2. 检查该请求是否在缓存中可用并且仍然有效(生命周期)
  3. 如果Request仍然有效,从Cache中取出,否则发出Request并保存其Response

我在 Android 中找到了 HttpResponseCache 类。它正在工作,但它没有像我期望的那样工作。

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

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 block 中,我必须创建第二个 HttpURLConnection,因为我无法在打开 URLConnection 后添加属性(这发生在 connection.getInputStream( )?!)。这是糟糕的编程吗?

毕竟,我发现 HttpResponseCache 的文档很少。我遇到了Volley: Fast Networking ,但这似乎更少记录,即使它提供了我需要的东西(请求排队和优先级排序......)。 您使用什么进行缓存?欢迎提供指向库和教程的任何链接。

更新我不针对低于 4.0 的 Android 版本(其他用户可能仍然感兴趣?)

最佳答案

HttpResponseCachevolley 的文档都很少。然而,我发现你可以很容易地扩展和调整 volley。如果您探索 volley 的源代码,尤其是:CacheEntry , CacheDispatcherHttpHeaderParser ,您可以看到它是如何实现的。

A CacheEntry serverDate, etag, ttlsofTtl 可以很好的表示缓存状态,还有 isExpired()refreshNeeded() 方法是为了方便。

CacheDispatcher也准确实现:

// 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尽力应对服务器 header :

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;

因此,请确保服务器发送正确的 header 以及荣誉 etag、时间戳和缓存控制 header 。

最后,您可以覆盖 RequestgetCacheEntry()类返回自定义 CacheEntry使缓存完全根据您的需要运行。

关于android - HttpResponseCache 不清除旧文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23741528/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com