美文网首页
retrofit2 + okhttp3 缓存实践 及 must-

retrofit2 + okhttp3 缓存实践 及 must-

作者: 熊er | 来源:发表于2017-05-03 15:37 被阅读0次

    需求

    • 手机无网络时能查看缓存数据
    • 有些数据变动较小,不必每次重新请求,缓解服务器压力

    结果

    • 所有返回均自动缓存,无网络时默认使用缓存数据 (如果有)
    • 所有请求默认复用时间为 10s,复用时间内新的请求不访问服务器,使用缓存数据 (如果有)
    • 可针对不同接口设置复用时间,也可不复用 (设置为 0s)

    条件

    GET请求

    实现

    • 设置缓存存储位置及大小
    Cache cache = new Cache(new File(getCacheDir(mContext), "responses"), 1024 * 1024 * 50)
    
    • 自定义缓存拦截器
    public class OKHttpCacheInterceptor implements Interceptor {
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (!isNetworkAvailable(App.getApplication())) {
                // 网络不可用时强制使用缓存
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build();
            } else if (TextUtils.isEmpty(request.header("Cache-Control"))) {
                // 网络可用 && 未设置复用时间 -> 默认复用时间为 10s
                request = request.newBuilder()
                        .header("Cache-Control", "private, max-stale=10")
                        .build();
            }
            Response response = chain.proceed(request);
            if (response.code() == 504) {
                throw new IOException("网络连接不可用");
            }
            return response.newBuilder()
                    .removeHeader("Pragma")
                    .build();
        }
    
        /**
         * 判断网络是否有效
         */
        private boolean isNetworkAvailable(Context context) {
            NetworkInfo netInfo = getNetworkInfo(context);
            return netInfo != null && netInfo.isAvailable();
        }
    
        /**
         * 获取当前网络信息
         */
        private NetworkInfo getNetworkInfo(Context context) {
            if (null != context) {
                ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                return mConnectivityManager.getActiveNetworkInfo();
            }
            return null;
        }
    }
    
    • 创建客户端实例
    new OkHttpClient.Builder()
        .addInterceptor(new OKHttpCacheInterceptor ())
        .cache(cache)
        .build()
    
    • Retrofit 初始化
    ClientAPI api = new Retrofit.Builder()
        .baseUrl(BASE_URL) 
        .addConverterFactory(converterFactory)
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .client(client)
        .build()
        .create(ClientAPI.class);
    
    • API接口
    public interface ClientAPI {
    
        /**
         * get 
         *
         * @return Daily
         */
        // 指定返回复用时间为 60s
        @Headers("Cache-Control: max-stale=60")
        @GET("news/latest")
        Observable<Daily> getDaily();
    
        ...
    }
    
    • 使用
    api.getDaily()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(daily -> {
            ...
         }, e -> Snackbar.make(binding.recycler, e.getMessage(), Snackbar.LENGTH_INDEFINITE).show());
    
    • 补充
      当服务器返回Cache-Control: must-revalidate时无法缓存,此时需加上另外一个网络拦截器(慎用
    @Override
      public Response intercept(Chain chain) throws IOException {
        return chain.proceed(chain.request())
            .newBuilder()
            .removeHeader("Pragma")
            .removeHeader("Cache-Control")
            .build();
      }
    
    addNetworkInterceptor(new OKHttpCacheNetworkInterceptor())
    

    相关文章

      网友评论

          本文标题:retrofit2 + okhttp3 缓存实践 及 must-

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