Amr Barakat Amr Barakat - 5 months ago 39
Android Question

HTTP Caching with Retrofit 2.0.x

I'm trying to cache some responses in my app using Retrofit 2.0, but I'm missing something.

I installed a caching file as follows:

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;
}


which creates a file in
/data/user/0/<PackageNmae>/cache/http

, then prepared a network interceptor as follows:

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();
}
}


my
Retrofit
and
OkHttpClient
instance:

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);


where
ProductsService.class
contains:

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


and

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


The question here is: How to make it access cached responses when device being offline?

Header of backend response are:

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

Answer

Finally I get the answer.

Network Interceptor should be as follow:

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;
}
}

then installing cache file is that simple

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.setCache(cache);
client.networkInterceptors().add(new CachingControlInterceptor());