使用分析的庫(kù)為:com.mcxiaoke.volley:library:1.0.19
0.如果開(kāi)啟緩存(默認(rèn)為開(kāi)啟)
//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慨亲,就請(qǐng)求網(wǎng)絡(luò)
//CacheDispatcher.java
Cache.Entry entry = mCache.get(request.getCacheKey());
2. 判斷緩存是否過(guò)期,如果過(guò)期就就請(qǐng)求網(wǎng)絡(luò)
//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. 判斷是否需要刷新儒洛,不需要刷新粱侣,則直接返回緩存的數(shù)據(jù)汛闸;
如果需要刷新核无,則先返回緩存數(shù)據(jù),再次請(qǐng)求網(wǎng)絡(luò)
//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.如果的響應(yīng)的statusCode為304款违,并且已經(jīng)從本地緩存數(shù)據(jù)callback一次了唐瀑,則忽略這個(gè)請(qǐng)求(不進(jìn)行callback),否則,繼續(xù)解析解析網(wǎng)絡(luò)數(shù)據(jù)插爹,并且返回(這就會(huì)出現(xiàn)回調(diào)兩次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;
}
補(bǔ)充:
那服務(wù)端如何判斷304的呢?
就需要先添加兩個(gè)請(qǐng)求頭
If-None-Match(從上次的響應(yīng)頭ETag獲仍病)
If-Modified-Since(從上次的響應(yīng)頭Last-Modified獲攘λ搿)
5.最后,如果請(qǐng)求使用緩存气嫁,則把獲取的網(wǎng)絡(luò)數(shù)據(jù)当窗,保存到本地。
//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");
}
附一手寫的圖寸宵,來(lái)理解ttl和softttl的關(guān)系
WechatIMG1.jpeg