我将很快完成一个项目,这个项目主要使用HTTPRequests来实现JSON和Images,所以我认为考虑缓存是个好主意。基本上我在寻找一个解决方案
HTTPRequest (f.e。3,6,12小时)我在安卓系统中找到了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();
}两个问题:
max-stale=60seconds设置为测试目的。但是,如果我在5分钟后调用相同的URL,它会告诉我,它正在从缓存中加载图像。我会假设,因为缓存中的HTTPRequest过期了,所以图像被重新加载了?还是必须自己清理缓存?catch块中,我必须创建第二个HttpURLConnection,因为我在打开URLConnection之后不能添加属性(这发生在connection.getInputStream()?!)。这是糟糕的编程吗?毕竟,我发现HttpResponseCache文档很少。我遇到了快速联网,但这似乎更少文档化,即使它提供了我所需要的东西(请求队列和优先级.)。您用来缓存什么?欢迎访问库、教程的链接。
更新--我的目标不是低于4.0的安卓版本(可能还在为其他用户提供更多?)
发布于 2014-05-29 06:16:05
HttpResponseCache和volley的文档都不多。但是,我发现您可以很容易地扩展和调整volley。如果您研究volley的源代码,特别是:CacheEntry、CacheDispatcher和HttpHeaderParser的源代码,您可以看到它是如何实现的。
CacheEntry包含serverDate、etag、ttl和sofTtl,它们可以很好地表示缓存状态,同时还具有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尽力处理服务器头:
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使缓存完全按照您的需要运行。
发布于 2014-05-28 22:33:38
发布于 2014-05-23 04:28:40
要启用缓存,只需使用以下代码在应用程序启动时安装HTTP响应缓存:
File httpCacheDir = new File(context.getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);是否需要从网络或缓存中获取资源,由HttpResponseCache来处理。缓存的年龄在资源请求的响应头中指定。例如,此图像指定缓存时间为43200秒。
通过使用以下apis,可以验证资源是从缓存还是从网络中获取的:
关于max-stale,您误解了它的目的。它用于允许过时的缓存响应。以下是来自rfc文档的定义:
指示客户端愿意接受超过其过期时间的响应。如果为max-stale分配了一个值,则客户端愿意接受超过其过期时间不超过指定秒数的响应。如果不给最大值赋值,则客户愿意接受任何年龄的陈腐响应。
关于缓存控制指令only-if-cached,仅在应用程序下载最新内容时需要显示某些内容时才使用它。因此,在异常处理程序中处理新HttpUrlConnection的问题不会出现。来自文档
有时,如果资源是立即可用的,则需要显示它们,而不是其他资源。这样您的应用程序就可以在等待下载最新数据时显示一些内容。若要将请求限制为本地缓存的资源,请添加唯一的if缓存指令。
一个建议是添加finally块,在这里通过调用断开连接释放连接。
https://stackoverflow.com/questions/23741528
复制相似问题