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的关系

WechatIMG1.jpeg

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值