美文网首页鱼乐
OkHttp3(Retrofit2)五种缓存模式的实现

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

作者: lvTravler | 来源:发表于2018-01-25 15:17 被阅读38次

    网上有许多写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;
    }
    

    }

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

    相关文章

      网友评论

        本文标题:OkHttp3(Retrofit2)五种缓存模式的实现

        本文链接:https://www.haomeiwen.com/subject/nsevaxtx.html