使用Retrofit 2.0.x进行HTTP缓存

Amr*_*kat 17 android caching retrofit okhttp

我正在尝试使用Retrofit 2.0在我的应用程序中缓存一些响应,但我遗漏了一些东西.

我安装了一个缓存文件,如下所示:

private static File httpCacheDir;
private static Cache cache;
try {
    httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
    httpCacheDir.setReadable(true);
    long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
    HttpResponseCache.install(httpCacheDir, httpCacheSize);
    cache = new Cache(httpCacheDir, httpCacheSize);
    Log.i("HTTP Caching", "HTTP response cache installation success");
} catch (IOException e) {
    Log.i("HTTP Caching", "HTTP response cache installation failed:" + e);
}

public static Cache getCache() {
        return cache;
    }
Run Code Online (Sandbox Code Playgroud)

在其中创建一个文件 /data/user/0/<PackageNmae>/cache/http ,然后准备一个网络拦截器如下:

public class CachingControlInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        // Add Cache Control only for GET methods
        if (request.method().equals("GET")) {
            if (ConnectivityUtil.checkConnectivity(getContext())) {
                // 1 day
                request.newBuilder()
                    .header("Cache-Control", "only-if-cached")
                    .build();
            } else {
                // 4 weeks stale
                request.newBuilder()
                    .header("Cache-Control", "public, max-stale=2419200")
                    .build();
            }
        }

        Response originalResponse = chain.proceed(chain.request());
        return originalResponse.newBuilder()
            .header("Cache-Control", "max-age=86400")
            .build();
    }
}
Run Code Online (Sandbox Code Playgroud)

RetrofitOkHttpClient实例:

OkHttpClient client = new OkHttpClient();
client.setCache(getCache());
client.interceptors().add(new MainInterceptor());
client.interceptors().add(new LoggingInceptor());
client.networkInterceptors().add(new CachingControlInterceptor());
Retrofit restAdapter = new Retrofit.Builder()
        .client(client)
        .baseUrl(Constants.BASE_URL)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();

productsService = restAdapter.create(ProductsService.class);
Run Code Online (Sandbox Code Playgroud)

其中ProductsService.class包括:

@Headers("Cache-Control: max-age=86400")
@GET("categories/")
Call<PagedResponse<Category>> listCategories();
Run Code Online (Sandbox Code Playgroud)

Call<PagedResponse<Category>> call = getRestClient().getProductsService().listCategories();
call.enqueue(new GenericCallback<PagedResponse<Category>>() {
      // whatever 
      // GenericCallback<T> implements Callback<T>
   }
});
Run Code Online (Sandbox Code Playgroud)

这里的问题是:如何让设备在设备离线时访问缓存响应?

后端响应的标题是:

Allow ? GET, HEAD, OPTIONS
Cache-Control ? max-age=86400, must-revalidate
Connection ? keep-alive
Content-Encoding ? gzip
Content-Language ? en
Content-Type ? application/json; charset=utf-8
Date ? Thu, 17 Dec 2015 09:42:49 GMT
Server ? nginx
Transfer-Encoding ? chunked
Vary ? Accept-Encoding, Cookie, Accept-Language
X-Frame-Options ? SAMEORIGIN
x-content-type-options ? nosniff
x-xss-protection ? 1; mode=block
Run Code Online (Sandbox Code Playgroud)

Amr*_*kat 14

最后我得到了答案.

网络拦截器应如下:

public class CachingControlInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        // Add Cache Control only for GET methods
        if (request.method().equals("GET")) {
            if (ConnectivityUtil.checkConnectivity(YaootaApplication.getContext())) {
                // 1 day
               request = request.newBuilder()
                        .header("Cache-Control", "only-if-cached")
                        .build();
            } else {
                // 4 weeks stale
               request = request.newBuilder()
                        .header("Cache-Control", "public, max-stale=2419200")
                        .build();
            }
        }

        Response originalResponse = chain.proceed(request);
        return originalResponse.newBuilder()
            .header("Cache-Control", "max-age=600")
            .build();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后安装缓存文件就这么简单

long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(new File(context.getCacheDir(), "http"), SIZE_OF_CACHE);
OkHttpClient client = new OkHttpClient();
client.cache(cache);
client.networkInterceptors().add(new CachingControlInterceptor());
Run Code Online (Sandbox Code Playgroud)

  • OkHttpClient 客户端 = new OkHttpClient.Builder().cache(cache).networkInterceptor(new CachingControlInterceptor()).build(); (5认同)

iag*_*een 8

在您CachingControlInterceptor,您创建新请求,但从未实际使用它们.您调用newBuilder并忽略结果,因此标题修改永远不会实际发送到任何位置.尝试这些值分配request,然后,而不是调用proceedchain.request()调用它request.

public class CachingControlInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        // Add Cache Control only for GET methods
        if (request.method().equals("GET")) {
            if (ConnectivityUtil.checkConnectivity(getContext())) {
                // 1 day
                request = request.newBuilder()
                    .header("Cache-Control", "only-if-cached")
                    .build();
            } else {
                // 4 weeks stale
                request = request.newBuilder()
                    .header("Cache-Control", "public, max-stale=2419200")
                    .build();
            }
        }

        Response originalResponse = chain.proceed(request);
        return originalResponse.newBuilder()
            .header("Cache-Control", "max-age=600")
            .build();
    }
}
Run Code Online (Sandbox Code Playgroud)