使用分析的库为: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. 判断缓存是否过期,如果过期就就请求网络
//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;
}
3. 判断是否需要刷新,不需要刷新,则直接返回缓存的数据;
如果需要刷新,则先返回缓存数据,再次请求网络
//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;
}
4.如果的响应的statusCode为304,并且已经从本地缓存数据callback一次了,则忽略这个请求(不进行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获取)
5.最后,如果请求使用缓存,则把获取的网络数据,保存到本地。
//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");
}
网友评论