okhttp3.4.1+retrofit2.1.0实现离线缓存

关于Retrofit+OkHttp的强大这里就很少说了,还没了解的同窗能够自行去百度。这篇文章主要讲如何利用Retrofit+OkHttp来实现一个较为简单的缓存策略:
即有网环境下咱们请求数据时,若是没有缓存或者缓存过时了,就去服务器拿数据,而且将新缓存保存下来,若是有缓存并且没有过时,则直接使用缓存。无网环境下咱们请求数据时,缓存没过时则直接使用缓存,缓存过时了则没法使用,须要从新联网获取服务器数据。缓存

缓存处理仍是颇有必要的,它有效的减小服务器负荷,下降延迟提高用户体验,同时也方便用户即便在没网络的状况下也能使用APP。服务器

以前一直有一个疑惑,既然Retrofit已是对OkHttp的一个封装了,为何还一直说Retrofit+OkHttp要一块儿搭配使用,后来才知道其实OKHttp很重要的一个做用,就是对一些网络请求的配置,例如链接超时,读取超时,以及一些缓存配置等。网络

 

1、添加依赖
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'ide

 

2、配置OkHttpClient(设置缓存路径和缓存文件大小) ui

File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache");//这里为了方便直接把文件放在了SD卡根目录的HttpCache中,通常放在context.getCacheDir()中
int cacheSize = 10 * 1024 * 1024;//设置缓存文件大小为10M
Cache cache = new Cache(httpCacheDirectory, cacheSize);
httpClient = new OkHttpClient.Builder()
             .connectTimeout(10, TimeUnit.SECONDS)//设置链接超时
             .readTimeout(10, TimeUnit.SECONDS)//读取超时
             .writeTimeout(10, TimeUnit.SECONDS)//写入超时
             .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加自定义缓存拦截器(后面讲解),注意这里须要使用.addNetworkInterceptor
             .cache(cache)//把缓存添加进来
             .build();

 

3、配置Retrofitspa

retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(httpClient)//把OkHttpClient添加进来
                .addConverterFactory(GsonConverterFactory.create())
                .build();

 

4、编写拦截器日志

  咱们知道其实Retrofit+OkHttp的缓存主要经过拦截器实现,因此主要作的功夫也在拦截器里面。code

 static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {

            Request request = chain.request();
            //网上不少示例代码都对在request请求前对其进行无网的判断,其实无需判断,无网自动访问缓存
//            if(!NetworkUtil.getInstance().isConnected()){
//                request = request.newBuilder()
//                        .cacheControl(CacheControl.FORCE_CACHE)//只访问缓存
//                        .build();
//            }
            Response response = chain.proceed(request);

            if (NetworkUtil.getInstance().isConnected()) {
                int maxAge = 60;//缓存失效时间,单位为秒
                return response.newBuilder()
                        .removeHeader("Pragma")//清除头信息,由于服务器若是不支持,会返回一些干扰信息,不清除下面没法生效
                        .header("Cache-Control", "public ,max-age=" + maxAge)
                        .build();
            } else {
                //这段代码设置无效
//                int maxStale = 60 * 60 * 24 * 28; // 无网络时,设置超时为4周
//                return response.newBuilder()
//                        .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
//                        .removeHeader("Pragma")
//                        .build();
            }
            return response;
        }
    };

到这里,其实已经能够实现了咱们开头所说的缓存效果了。blog

  可是,上面设置的每一个接口缓存时间都同样,例如我如今想让不一样接口的缓存数据失效时间都不同,甚至有些接口不缓存数据,应该怎么作呢?其实也很简单接口

首先咱们只须要在接口前面添加@Headers参数(max-age表明缓存时间,单位为秒,示例中表示缓存失效时间为60s,想要多少时间能够自行设置),不设置@Headers参数则不进行缓存。

    @Headers("Cache-Control:public ,max-age=60")
    @GET("getBusiness.action")//商店信息
    Call<RestaurantInfoModel> getRestaurantInfo(@Query("userId") String userId,@Query("businessId") String businessId);

 同时,咱们的缓存拦截器也要作下简单的修改(去掉了以前的注释代码)

    static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {

            Request request = chain.request();
            Response response = chain.proceed(request);

            if (NetworkUtil.getInstance().isConnected()) {
                //获取头部信息
                String cacheControl =request.cacheControl().toString();
                return response.newBuilder()
                        .removeHeader("Pragma")//清除头信息,由于服务器若是不支持,会返回一些干扰信息,不清除下面没法生效
                        .header("Cache-Control", cacheControl)
                        .build();
            }
            return response;
        }
    };

 

*注意:

1.只能缓存Get请求的接口,不能缓存Post请求的接口

2.OkHttpClient须要用.addNetworkInterceptor添加缓存拦截器,不能使用.addInterceptor,也无需二者同时使用。

3.此方法无需服务器端任何操做,适用于服务器端没有其余缓存策略,若是服务器端有本身的缓存策略代码应该作相应的修改,以适应服务器端。

 

附上全部代码:

/**
 * 简单封装的Retroit初始化类
 */
public class initRetrofit {
    private static String baseUrl = "http://202.171.212.154:8080/hh/";
    private static OkHttpClient httpClient;
    private static Retrofit retrofit;

    public static Retrofit initRetrofit() {
        //缓存路径和大小
        File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache");
        int cacheSize = 10 * 1024 * 1024;
        Cache cache = new Cache(httpCacheDirectory, cacheSize);

        //日志拦截器
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        httpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)//设置链接超时
                .readTimeout(10, TimeUnit.SECONDS)//读取超时
                .writeTimeout(10, TimeUnit.SECONDS)//写入超时
                .addInterceptor(interceptor)//添加日志拦截器
                .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加缓存拦截器
                .cache(cache)//把缓存添加进来
                .build();

        retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(httpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        return retrofit;
    }

    public static RetrofitAPI getService() {
        return initRetrofit().create(RetrofitAPI.class);
    }

//    //缓存拦截器,不一样接口不一样缓存
//    static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
//        @Override
//        public Response intercept(Chain chain) throws IOException {
//
//            Request request = chain.request();
//            Response response = chain.proceed(request);
//
//            if (NetworkUtil.getInstance().isConnected()) {
//                String cacheControl =request.cacheControl().toString();
//                return response.newBuilder()
//                        .removeHeader("Pragma")//清除头信息,由于服务器若是不支持,会返回一些干扰信息,不清除下面没法生效
//                        .header("Cache-Control", cacheControl)
//                        .build();
//            }
//            return response;
//        }
//    };

    //缓存拦截器,统一缓存60s
    static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {

            Request request = chain.request();
            Response response = chain.proceed(request);

            if (NetworkUtil.getInstance().isConnected()) {
                int maxAge = 60*60*24*2;//缓存失效时间,单位为秒
                return response.newBuilder()
                        .removeHeader("Pragma")//清除头信息,由于服务器若是不支持,会返回一些干扰信息,不清除下面没法生效
                        .header("Cache-Control", "public ,max-age=" + maxAge)
                        .build();
            }
            return response;
        }
    };
}
相关文章
相关标签/搜索