OkHttp3源码解析--拦截器CacheInterceptor

CacheInterceptor顾名思义,它是和缓存的管理和获取相关的:

  • 从缓存中匹配Request的请求响应结果,根据缓存策略,如果能找到可用的缓存,直接返回;

  • 将服务器返回的请求结果,写入到缓存中;

  • 更新现有缓存;

设置缓存

//缓存文件夹
File cacheFile = new File(getExternalCacheDir().toString(),"cache");
//缓存大小为10M
int cacheSize = 10 * 1024 * 1024;
//创建缓存对象
final Cache cache = new Cache(cacheFile,cacheSize);
​
OkHttpClient client = new OkHttpClient.Builder()
  .cache(cache)//设置缓存
  .build();
.......

看下CacheInterceptor它的代码:

CacheInterceptor

public final class CacheInterceptor implements Interceptor {
  
  final InternalCache cache;//InternalCache在构造器中传进来
  //设置缓存信息进来
  public CacheInterceptor(InternalCache cache) {
    this.cache = cache;
  }@Override public Response intercept(Chain chain) throws IOException {
    
    //首先,通过我们的Request对象,获取候选缓存
    Response cacheCandidate = cache != null
        ? cache.get(chain.request())
        : null;
    long now = System.currentTimeMillis();
    //创建缓存策略
    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
    Request networkRequest = strategy.networkRequest;
    Response cacheResponse = strategy.cacheResponse;
    if (cache != null) {
      cache.trackResponse(strategy);
    }
    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
    }// If we're forbidden from using the network and the cache is insufficient, fail.
    //不能网络访问,并且缓存不可用,这次请求失败,创建一个Response对象,返回给前面的拦截器
    if (networkRequest == null && cacheResponse == null) {
      return new Response.Builder()
          .request(chain.request())
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(Util.EMPTY_RESPONSE)
          .sentRequestAtMillis(-1L)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();
    }// If we don't need the network, we're done.
    //不需要进行网络访问,缓存可用,使用缓存就可以了,不需要在执行下面的拦截器,直接返回Response对象
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }
    
    //需要进行网络访问,继续执行后面的拦截器
    Response networkResponse = null;
    try {
      //继续执行下一个拦截器,即ConnectInterceptor
      networkResponse = chain.proceed(networkRequest);
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (networkResponse == null && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }
    //网络访问,响应结果返回,接下来就是更新缓存,写入缓存
    // If we have a cache response too, then we're doing a conditional get.
    if (cacheResponse != null) {
      if (networkResponse.code() == HTTP_NOT_MODIFIED) {
        Response response = cacheResponse.newBuilder()
            .headers(combine(cacheResponse.headers(), networkResponse.headers()))
            .sentRequestAtMillis(networkResponse.sentRequestAtMillis())
            .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
        networkResponse.body().close();// Update the cache after combining headers but before stripping the
        // Content-Encoding header (as performed by initContentStream()).
        cache.trackConditionalCacheHit();
        cache.update(cacheResponse, response);//更新缓存
        return response;
      } else {
        closeQuietly(cacheResponse.body());
      }
    }
​
    Response response = networkResponse.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build();if (cache != null) {
      if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
        // Offer this request to the cache.
        CacheRequest cacheRequest = cache.put(response);
        return cacheWritingResponse(cacheRequest, response);
      }if (HttpMethod.invalidatesCache(networkRequest.method())) {
        try {
          cache.remove(networkRequest);
        } catch (IOException ignored) {
          // The cache cannot be written.
        }
      }
    }
    //将请求结果返回给上一个拦截器,即BridgeInterceptor
    return response;
  }

主要流程如下:

  • 首先,根据Request对象的URL,从缓存中获取备选缓存;

  • 然后,根据缓存策略,判断当前缓存是否可用;

  • 如果缓存可用,直接将缓存返回给前端即可;否则,进行下面操作;

  • 缓存不可用,需要执行网络访问请求;

  • 网络访问完成,根据返回结果,更新缓存,保存缓存;

  • 将请求结果返回给前端;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值