OkHttp3缓存似乎未使用Retrofit 2进行检查

时间:2016-11-10 16:48:04

标签: android caching retrofit2 okhttp3

我尝试使用Retrofit(2.1.0)和OkHttp(3.3.1)设置HTTP缓存。我看过很多与这个主题相关的帖子,但都没有帮助。

我写了一些单元测试来查看缓存是如何工作的。它工作正常,但一旦集成在我的应用程序中,魔术就结束了。我将首先向您展示我的实施,然后解释我的一些调查。

首先,这是我的Retrofit实例化:

    OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
    HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);

    OkHttpClient client = httpBuilder
            .addNetworkInterceptor(INTERCEPTOR_RESPONSE_SET_CACHE)
            .addNetworkInterceptor(INTERCEPTOR_REQUEST_ADD_CHECKSUM)
            .addInterceptor(loggingInterceptor)
            .cache(cacheHttpClient).build();

    Retrofit retrofit = new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .baseUrl(BASE_URL)
            .build();

这是拦截器添加标头来设置缓存控制:

    private final Interceptor INTERCEPTOR_RESPONSE_SET_CACHE = new Interceptor() {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Response response = chain.proceed(chain.request());
            response = response.newBuilder()
                    .header("Cache-Control", "max-age=600") //+ Integer.toString(3600 * 5)
                    .build();
            return response;
        }
    };

最后一个拦截器添加了2个URL参数:

 private static final Interceptor INTERCEPTOR_REQUEST_ADD_CHECKSUM = new Interceptor() {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            HttpUrl url = chain.request().url();
            url = url.newBuilder().addQueryParameter("rd", "random1").addQueryParameter("chk","check1").build();
            Request request = chain.request().newBuilder().url(url).build();
            return chain.proceed(request);
        }
    };

最后,我服务的单一方法:

 @Headers("Cache-Control: public, max-stale=500")
 @GET("/get_data")
 Call<DataResponse> getData(@Query("year") int year, @Query("month") int month, @Query("day") int day);

关于我的调查,我设置了拦截器记录器(应用程序端,而不是网络)以查看发生了什么。我可以看到诸如&#34; Cache-Control之类的行:public,max-stale = 500&#34;在我的日志中。这意味着(至少对我而言)标题应该为OkHttp客户端提供检查缓存的机会。

缓存本身似乎已正确初始化。当我创建它时,我强制初始化并记录缓存中存在的所有URL。以下是它的实现方式:

File httpCacheDirectory = new File(getCacheDir(), "responses");
        httpCacheDirectory.getParentFile().mkdirs();
        int cacheSize = 10 * 1024 * 1024; // 10 MiB
        Cache cache = new Cache(httpCacheDirectory, cacheSize);
        try {
            cache.initialize();
            Iterator<String> iterator = cache.urls();
            Log.i(TAG, "URLs in cacheHttpClient : ");
            while (iterator.hasNext()) {
                Log.i(TAG, iterator.next());
            }
        } catch (IOException e) {
            e.printStackTrace();
            Log.i(TAG, "CACHE NOT INIT");
        }

当我使用Wifi启动我的应用程序时,我得到了预期的回复。然后我杀了我的应用程序,禁用Wifi并重新启动应用程序。我希望此时缓存能够提供数据。但它失败了,我只能在日志中看到OkHttp打印的行:

  

HTTP FAILED:java.net.UnknownHostException:无法解析主机   &#34; my-domain.com&#34;:没有与主机名相关联的地址

最后,在RFC 2616中,可以阅读:

  

max-stale:表示客户端愿意接受响应   已超过其到期时间。如果为max-stale分配了一个   价值,然后客户愿意接受有的回应   超过其到期时间不超过指定的数量   秒。如果没有为max-stale分配值,那么客户端就是   愿意接受任何年龄的陈旧回应。

当我没有指定一个值时,它实际上是有效的(即使在Wifi关闭时我也会得到响应)。现在,这是我找到的唯一方法#34; work&#34;。所以也许我只是误解了缓存控制指令!?

此时我真的很困惑。我真的希望能够使用OkHttp缓存系统,但不知怎的,我错过了一些东西。

感谢您阅读所有文字!

1 个答案:

答案 0 :(得分:1)

使用此方法创建缓存的okkhttpclient

private OkHttpClient createCachedClient(final Context context) {
        File httpCacheDirectory = new File(context.getCacheDir(), "cache_file");

        Cache cache = new Cache(httpCacheDirectory, 20 * 1024 * 1024);
        OkHttpClient okHttpClient = new OkHttpClient();
        okHttpClient.setCache(cache);
        okHttpClient.interceptors().add(
                new Interceptor() {
                    @Override
                    public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
                        Request originalRequest = chain.request();
                        String cacheHeaderValue = isOnline(context)
                                ? "public, max-age=2419200"
                                : "public, only-if-cached, max-stale=2419200" ;
                        Request request = originalRequest.newBuilder().build();
                        com.squareup.okhttp.Response response = chain.proceed(request);
                        return response.newBuilder()
                                .removeHeader("Pragma")
                                .removeHeader("Cache-Control")
                                .header("Cache-Control", cacheHeaderValue)
                                .build();
                    }
                }
        );
        okHttpClient.networkInterceptors().add(
                new Interceptor() {
                    @Override
                    public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
                        Request originalRequest = chain.request();
                        String cacheHeaderValue = isOnline(context)
                                ? "public, max-age=2419200"
                                : "public, only-if-cached, max-stale=2419200" ;
                        Request request = originalRequest.newBuilder().build();
                        com.squareup.okhttp.Response response = chain.proceed(request);
                        return response.newBuilder()
                                .removeHeader("Pragma")
                                .removeHeader("Cache-Control")
                                .header("Cache-Control", cacheHeaderValue)
                                .build();
                    }
                }
        );
        return okHttpClient;
    }

    private boolean isOnline(Context context) {
        ConnectivityManager connectivity = (ConnectivityManager) _context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            NetworkInfo[] info = connectivity.getAllNetworkInfo();
            if (info != null)
                for (int i = 0; i < info.length; i++)
                    if (info[i].getState() == NetworkInfo.State.CONNECTED) {
                        return true;
                    }
        }
        return false;


        }

调用createCachedClient()方法创建OkHttpClient添加此客户端进行改造

OkHttpClient okHttpClient = createCachedClient(MainActivity.this);
Retrofit retrofit=new Retrofit.Builder()
         .client(okHttpClient)
         .baseUrl(API)
         .addConverterFactory(GsonConverterFactory
         .create()).build();

将此权限添加到清单

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

如果互联网第一次可用,它将调用服务并缓存请求,下次最多2419200毫秒,它将使用缓存来响应。即使设备离线,也不会达到2419200毫秒的服务器。