Volley的缓存策略
Posted ihrthk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Volley的缓存策略相关的知识,希望对你有一定的参考价值。
使用分析的库为:com.mcxiaoke.volley:library:1.0.19
0.如果开启缓存(默认为开启)
//Request.java
/** Whether or not responses to this request should be cached. */
private boolean mShouldCache = true;
/**
* Set whether or not responses to this request should be cached.
*
* @return This Request object to allow for chaining.
*/
public final Request<?> setShouldCache(boolean shouldCache)
mShouldCache = shouldCache;
return this;
1. 获取Cache.Entry,如果为null,就请求网络
//CacheDispatcher.java
Cache.Entry entry = mCache.get(request.getCacheKey());
2.默认缓存的硬过期和软过期相同(ttl=softtl)
//HttpHeaderParser.java
// 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;
3. 判断缓存硬过期和软过期的方法
/** True if the entry is expired. */
public boolean isExpired()
return this.ttl < System.currentTimeMillis();
/** True if a refresh is needed from the original data source. */
public boolean refreshNeeded()
return this.softTtl < System.currentTimeMillis();
4. 如果缓存硬过期就请求网络
//CacheDispatcher.java
// 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;
/** True if the entry is expired. */
public boolean isExpired()
return this.ttl < System.currentTimeMillis();
public long getTtl()
long ttl;
if (hasCacheControl())
softExpire = now + maxAge * 1000;
ttl = mustRevalidate ? softExpire : softExpire + staleWhileRevalidate * 1000;
else
ttl = now + (serverExpires - serverDate);
return ttl;
public boolean hasCacheControl()
String headerValue = headers.get("Cache-Control");
boolean hasCacheControl = headerValue != null;
return hasCacheControl;
/*softExpire和softTtl是一样的*/
public long getSoftTtl()
boolean softExpire = hasCacheControl() ? now + maxAge * 1000 : now + (serverExpires - serverDate);
return softExpire;
5. 如果缓存没有硬过期,则解析缓存数据
//CacheDispatcher.java
// 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");
6.接下来判断缓存是否软过期,如果缓存没有软过期,则直接返回缓存的数据;如果已经过期了,则先返回缓存数据,再次请求网络
//CacheDispatcher.java
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.
final Request<?> finalRequest = request;
mDelivery.postResponse(request, response, new Runnable()
@Override
public void run()
try
mNetworkQueue.put(finalRequest);
catch (InterruptedException e)
// Not much we can do about this.
);
/** True if a refresh is needed from the original data source. */
public boolean refreshNeeded()
return this.softTtl < System.currentTimeMillis();
/*softExpire和softTtl是一样的*/
public long getSoftTtl()
boolean softExpire = hasCacheControl() ? now + maxAge * 1000 : now + (serverExpires - serverDate);
return softExpire;
7.如果的响应的statusCode为304,并且响应已经返回过一次,则忽略这个请求(即不在主线程callback)。否则,继续解析解析网络数据,并且返回(这就会出现回调两次callback的情况)。
//NetworkDispatcher.java
// If the server returned 304 AND we delivered a response already,
// we're done -- don't deliver a second identical response.
if (networkResponse.notModified && request.hasHadResponseDelivered())
request.finish("not-modified");
continue;
补充:
那服务端如何判断304的呢?
就需要先添加两个请求头
If-None-Match(从上次的响应头ETag获取)
If-Modified-Since(从上次的响应头Last-Modified获取)
8.最后,如果请求使用缓存,则把获取的网络数据,保存到本地。
//NetworkDispatcher.java
// Write to cache if applicable.
// TODO: Only update cache metadata instead of entire record for 304s.
if (request.shouldCache() && response.cacheEntry != null)
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
附一手写的图,来理解ttl和softttl的关系
以上是关于Volley的缓存策略的主要内容,如果未能解决你的问题,请参考以下文章
当重试策略设置为 0 时,Android Volley 向服务器发出 2 个请求