retrofit2.0缓存设置

前言

在 Android 开发过程中,Retrofit 的出现绝对是里程碑式的,说起 Retrofit 不得不说 square,这绝对是家l好公司,业界良心。

回到今天的主题,OKHttp3 网络层 缓存实现与分析。有人可能会说,你这怎么又扯到 OKHttp3 了,好了废话不扯。

完整项目 托管在 github 上,直达电梯:豆瓣电影客户端 github

代码分析

本文主要还是关于实现层面的讲解,只是豆瓣电影客户端其中一个功能。先贴代码(经过测试的代码)。

 class Factory {
        private static String TAG = "factory";
        public static MovieApiService createService(final Context context) {
            //日志拦截器
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            /** * 获取缓存 */
            Interceptor baseInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    if (!AppUtil.isNetWorkAvailable(context)) {
                        /** * 离线缓存控制 总的缓存时间=在线缓存时间+设置离线缓存时间 */
                        int maxStale = 60 * 60 * 24 * 28; // 离线时缓存保存4周,单位:秒
                        CacheControl tempCacheControl = new CacheControl.Builder()
                                .onlyIfCached()
                                .maxStale(maxStale, TimeUnit.SECONDS)
                                .build();
                        request = request.newBuilder()
                                .cacheControl(tempCacheControl)
                                .build();
                        Log.i(TAG, "intercept:no network ");
                    }
                    return chain.proceed(request);
                }
            };
            //只有 网络拦截器环节 才会写入缓存写入缓存,在有网络的时候 设置缓存时间
            Interceptor rewriteCacheControlInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    Response originalResponse = chain.proceed(request);
                    int maxAge = 1 * 60; // 在线缓存在1分钟内可读取 单位:秒
                    return originalResponse.newBuilder()
                            .removeHeader("Pragma")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
                            .removeHeader("Cache-Control")
                            .header("Cache-Control", "public, max-age=" + maxAge)
                            .build();
                }
            };
            //设置缓存路径 内置存储
            //File httpCacheDirectory = new File(context.getCacheDir(), "responses");
            //外部存储
            File httpCacheDirectory = new File(context.getExternalCacheDir(), "responses");
            //设置缓存 10M
            int cacheSize = 10 * 1024 * 1024;
            Cache cache = new Cache(httpCacheDirectory, cacheSize);

            OkHttpClient client = new OkHttpClient.Builder()
                    .cache(cache)
                    .addInterceptor(logging)
                    .addInterceptor(baseInterceptor)
                    .addNetworkInterceptor(rewriteCacheControlInterceptor)
                    .connectTimeout(15, TimeUnit.SECONDS)
                    .build();

            return new Retrofit.Builder()              .addConverterFactory(GsonConverterFactory.create())            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()
                    .baseUrl(BASEURL)
                    .client(client)
                    .build()
                    .create(MovieApiService.class);
        }
    }

  
  
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

代码中有详细的注释,下面简要说下 此代码的逻辑:

上面 提到了 OKHttpClient 拦截器的概念,可以参看 okhttp 。

代码中实现了3个拦截器(Interceptor),分别是logging 、baseInterceptor 和 rewriteCacheControlInterceptor。三个拦截器分别有不同的作用,logging 实现是把请求参数和 response 作为控制台日志方式打印出来;baseInterceptor 是根据请求环境进行不同策略的操作(比如断网环境下的策略);rewriteCacheControlInterceptor 是网络层面的操作。

1、logging

logging 是 HttpLoggingInterceptor 不再过多的介绍。

2、baseInterceptor

代码实现:

            /** * 获取缓存 */
            Interceptor baseInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    if (!AppUtil.isNetWorkAvailable(context)) {
                        /** * 离线缓存控制 总的缓存时间=在线缓存时间+设置离线缓存时间 */
                        int maxStale = 60 * 60 * 24 * 28; // 离线时缓存保存4周,单位:秒
                        CacheControl tempCacheControl = new CacheControl.Builder()
                                .onlyIfCached()
                                .maxStale(maxStale, TimeUnit.SECONDS)
                                .build();
                        request = request.newBuilder()
                                .cacheControl(tempCacheControl)
                                .build();
                        Log.i(TAG, "intercept:no network ");
                    }
                    return chain.proceed(request);
                }
            };
  
  
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

其中 AppUtil.isNetWorkAvailable(context) 是判断网络是否可用的方法。此处的 maxStale 值是在无网络的情况下缓存时间。在这时间内,如果你没钱也一直没蹭到网络,则一直读取缓存的数据。

其中非常重要的一点:

离线缓存控制 总缓存时间=在线缓存时间+设置离线时的缓存时间

即 maxStale和下文提到的 maxAge 的和。

3、rewriteCacheControlInterceptor

         Interceptor rewriteCacheControlInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    Response originalResponse = chain.proceed(request);
                    int maxAge = 1 * 60; // 在线缓存在1分钟内可读取 单位:秒
                    return originalResponse.newBuilder()
                            .removeHeader("Pragma")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
                            .removeHeader("Cache-Control")
                            .header("Cache-Control", "public, max-age=" + maxAge)
                            .build();
                }
            };
  
  
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注意 如果设置了允许缓存,只有在 网络拦截器 层面,OKHttp的缓存机制才会起作用。

设置缓存文件路径

 //设置缓存路径 内置存储
            //File httpCacheDirectory = new File(context.getCacheDir(), "responses");
            //外部存储
            File httpCacheDirectory = new File(context.getExternalCacheDir(), "responses");
            //设置缓存 10M
            int cacheSize = 10 * 1024 * 1024;
            Cache cache = new Cache(httpCacheDirectory, cacheSize);
  
  
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

代码中提到 内置存储和外部存储的问题,对一些容积比较大持久化数据,Android 官方推荐保存在外部存储空间内,通过 context.getExternalCacheDir()的方式,获取外部存储空间的路径。可以放心的是 此路径是系统维护的路径(大概是这样子 `/storage/emulated/0/android/data/包名/cache/ , 在应用卸载的情况下,此目录也会随着一并删除)。

OkHttpClient client = new OkHttpClient.Builder()
                    .cache(cache)
                    .addInterceptor(logging)
                    .addInterceptor(baseInterceptor)
                    .addNetworkInterceptor(rewriteCacheControlInterceptor)
                    .connectTimeout(15, TimeUnit.SECONDS)
                    .build();
  
  
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意 rewriteCacheControlInterceptor 要通过 addNetworkInterceptor()添加,否则缓存会有异常.

你可能感兴趣的:(retrofit2.0缓存设置)