鱼乐

OkHttp3(Retrofit2)五种缓存模式的实现

2018-01-25  本文已影响38人  lvTravler

网上有许多写OKhttp3缓存的文章,例如:
【Okhttp3结合Retrofit2 实现缓存】https://www.jianshu.com/p/74d2c10c3eba?from=timeline
【使用Retrofit和Okhttp3实现网络缓存】https://www.jianshu.com/p/34f73e571ecb
【okhttp3缓存实践】http://blog.csdn.net/wuhengde/article/details/54927096
这些文章都很不错,但还是有一些小小的瑕疵,这里我参考他们的文章结合自己的实践简单封装了Okhttp3的五种缓存方式供大家参考,如有错误还请不吝赐教。

主要知识点:

  1. OkHttp的缓存机制通过拦截器(Interceptor)来实现,通过addInterceptor()(应用拦截器)和addNetworkInterceptor()(网络拦截器)来添加;
  2. Interceptor的访问机制:在有网状态下先访问应用拦截器,再访问网络拦截器;而在无网络状态只访问应用拦截器;
  3. 缓存实现思路:在网络拦截器中请求网络数据并缓存到本地,而后在应用拦截器中访问本地缓存;
  4. 缓存类别:缓存可分为在线缓存和离线缓存,在线缓存例如客户端在短时间内多次请求网络数据,这时就可将在线缓存数据返回,但是要注意这个缓存的有效期不要太长了,否则服务端数据改变了不能及时更新;离线缓存例如在无网络状态下想要客户端还能有数据展示,就需要长时间缓存到本地并在有网状态下及时更新缓存数据;
  5. 在线缓存与离线缓存的异同:两者都是一个缓存文件,只是header设置不同,例如在线缓存header("max-age=30"),而离线缓存header("if-only-cached,max-age=86400"),两者可以通过删除header和设置header进行切换。

public class OkHttpUtil {

public static class CacheStrategy {
    /**
     * 只读取网络数据
     */
    public static final int ONLY_NETWORK = 0x0101;
    /**
     * 只读取缓存数据
     */
    public static final int ONLY_CACHE = 0x0102;
    /**
     * 有网读取网络数据,无网读取缓存
     */
    public static final int IF_NET_NETWORK__IF_NOT_CACHE = 0x0103;
    /**
     * 在线缓存有效时读取缓存,无效时读取网络数据
     */
    public static final int IF_NET_EXCEED_NETWORK_ELSE_CACHE = 0x0104;
    /**
     * 有网在线缓存有效时读取缓存,无效时读取网络数据;无网直接读取缓存
     */
    public static final int IF_NET_EXCEED_NETWORK_ELSE_CACHE__IF_NOT_CACHE = 0x0105;
}


/**
 * 创建OkHttp客户端,并实现多种缓存模式
 * 拦截器:
 * 1.应用拦截器:addInterceptor
 * 2.网络拦截器:addNetworkInterceptor
 *
 * @return
 */
public static OkHttpClient createOkHttpClient(final int cacheStrategy) {
    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    builder.addInterceptor(new Interceptor() {//应用拦截器——无网状态下的拦截
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response;
            switch (cacheStrategy) {
                case CacheStrategy.ONLY_CACHE:
                    response = readCache(chain, request);
                    break;
                case CacheStrategy.IF_NET_NETWORK__IF_NOT_CACHE:
                    if (NetworkUtil.isNetworkAvailable()) {
                        response = readNetwork(chain, request);
                    } else {
                        response = readCache(chain, request);
                    }
                    break;
                case CacheStrategy.IF_NET_EXCEED_NETWORK_ELSE_CACHE__IF_NOT_CACHE:
                    if (NetworkUtil.isNetworkAvailable()) {
                        response = readNetwork(chain, request);
                    } else {
                        response = readCache(chain, request);
                    }
                    break;
                case CacheStrategy.ONLY_NETWORK:
                case CacheStrategy.IF_NET_EXCEED_NETWORK_ELSE_CACHE://当设置了在线缓存,只要缓存没过期OkHttp会自动先获取缓存
                default:
                    response = readNetwork(chain, request);
                    break;
            }
            return response;
        }
    });
    if (cacheStrategy != CacheStrategy.ONLY_NETWORK) {
        File httpCacheDir = new File(BaseApp.getContext().getExternalCacheDir(), Config.HTTP_CACHE_FILE_NAME);
        final Cache cache = new Cache(httpCacheDir, Config.HTTP_CACHE_SIZE);
        builder.addNetworkInterceptor(new Interceptor() {//网络拦截器——有网状态下的拦截
            @Override
            public Response intercept(Chain chain) throws IOException {
                Response originalResponse = chain.proceed(chain.request());
                int maxAge = Config.HTTP_ONLINE_CACHE_TIME;//在线缓存时间
                return originalResponse.newBuilder()
                        .removeHeader("Pragma")//清除头信息
                        .removeHeader("Cache-Control")
                        .body(new progressResponse(originalResponse))//获取进度
                        .header("Cache-Control", "public,max-age=" + maxAge)//若是0则为不设置缓存
                        .build();
            }
        }).cache(cache);//设置缓存;
    }
    builder.connectTimeout(Config.REQUEST_TIMEOUT, TimeUnit.SECONDS)//设置10s超时时间
            .retryOnConnectionFailure(true);//连接失败后尝试再次连接
    return builder.build();
}

private static Response readNetwork(Interceptor.Chain chain, Request request) throws IOException {
    return chain.proceed(request);
}

private static Response readCache(Interceptor.Chain chain, Request request) throws IOException {
    Response response;
    CacheControl cacheControl = new CacheControl.Builder()
            .onlyIfCached()
            .maxStale(Config.HTTP_OFFLINE_CACHE_TIME, TimeUnit.DAYS)
            .build();
    response = chain.proceed(request.newBuilder()
            .cacheControl(cacheControl)
            .build());
    return response;
}

}

后记:如有不同见解或疑惑,欢迎留言,如果觉得不错可以来个赞!点个赞!

上一篇 下一篇

猜你喜欢

热点阅读