需求

  • 有网络的情况下总是去访问服务器获取最新的数据,并把数据缓存到本地
  • 无网络的情况下直接去缓存里找数据,如果没有找到就抛出异常 (提示:当前没有网络连接)
  • 部分配置缓存的接口启用缓存

实现

  • 主要就是用到了okhttp的拦截器,通过修改请求头的Cache-Control来实现缓存
  • 关于okhttp的拦截器我们用到了两个方法addInterceptor和addNetworkInterceptor

addInterceptor和addNetworkInterceptor

addInterceptor优先addNetworkInterceptor执行 有网络的情况下addInterceptor和addNetworkInterceptor都会执行 没有网络的情况下addInterceptor执行,而addNetworkInterceptor不会执行 没有网络但是有缓存的情况下addInterceptor会执行,而addNetworkInterceptor不会执行

代码实现

  1. public class CacheInterceptor implements Interceptor {
  2. @Override
  3. public Response intercept(Chain chain) throws IOException {
  4. Request request = chain.request();
  5. // 拦截请求头 判断哪些接口配置上了缓存(该配置是在retrofit上配置)
  6. String cacheControl = request.cacheControl().toString();
  7. // 如果没有配置过 那么就是走正常的访问,这里直接return回去了,并没有对请求做处理
  8. if(TextUtils.isEmpty(cacheControl)) {
  9. return chain.proceed(builder.build());
  10. }
  11. // 如果没有网络的情况下,并且配置了缓存,那么我们就设置强制读取缓存,没有读到就抛异常 503,但是并不会去服务器请求数据
  12. if (!NetworkUtils.isConnected()) {
  13. // 缓存一周
  14. int offlineCacheTime = 60 * 60 * 24 * 7;
  15. request = request.newBuilder()
  16. // only-if-cached 强制使用缓存
  17. // max-stale 即使这个缓存已经过期了,只要在max-stale这个时间内,还可以使用过期的缓存
  18. .header("Cache-Control", "public, only-if-cached, max-stale=" + offlineCacheTime)
  19. .build();
  20. }
  21. return chain.proceed(request);
  22. }
  23. }
  1. // 跟平时retorfit写法一样,只是添加了@Headers这个配置
  2. @Headers("Cache-Control:public, max-age=0")
  3. @GET("user/account/getStudent/v1.0")
  4. Observable<BaseResBean<UserBean>> getUserInfo(@QueryMap HashMap<String, Object> map);
  1. public OkHttpClient provideOkHttpClient(Context context) {
  2. // 先进行缓存目录的配置
  3. File httpCacheDirectory = new File(context.getCacheDir(), "OkHttpCache");
  4. // 设置缓存文件大小为10M
  5. int cacheSize = 10 * 1024 * 1024;
  6. Cache cache = new Cache(httpCacheDirectory, cacheSize);
  7. OkHttpClient.Builder builder = new OkHttpClient.Builder()
  8. ...
  9. // 缓存配置
  10. .cache(cache)
  11. // 启用缓存拦截器
  12. .addInterceptor(new CacheInterceptor());
  13. return builder.build();
  14. }