home.


Tagged: android-okhttp


Android: Using OkHTTP's response cache (Retrofit)

If you’re using Refrofit with OkHTTP, or just OkHTTP on its own, you can set it up to cache your responses.

Update: There’s a simpler version of this for OkHTTP3 and Retrofit 2, although this shows you how to directly access the cache, which you may not need.

This is an example in OkHTTP 2.0.

OkHttpClient ok = new OkHttpClient();
try {
    Cache responseCache = new Cache(context.getCacheDir(), SIZE_OF_CACHE);
    ok.setCache(responseCache);
} catch (Exception e) {
    Log.d(TAG, "Unable to set http cache", e);
}
ok.setReadTimeout(30, TimeUnit.SECONDS);
ok.setConnectTimeout(30, TimeUnit.SECONDS);

If you cache is large enough, OkHTTP will start to cache your responses. And if your server uses Etags or similar, it will returned cached responses on 304s.

You can also access this cache to return cached responses before making a network response.

public FilterInputStream getFromCache(String url) throws Exception {
    DiskLruCache cache = DiskLruCache.open(context.getCacheDir(), 201105, 2, SIZE_OF_CACHE);    
    cache.flush();
    String key = Util.hash(url);
    final DiskLruCache.Snapshot snapshot;
    try {
        snapshot = cache.get(key);
        if (snapshot == null) {
            return null;
        }
    } catch (IOException e) {
        return null;
    }

    FilterInputStream bodyIn = new FilterInputStream(snapshot.getInputStream(1)) {
        @Override
        public void close() throws IOException {
            snapshot.close();
            super.close();
        }
    };

    return bodyIn;
}

This opens the DiskLruCache that OkHTTP uses internally, makes a hash out of your URL using an OkHTTP utility method, then returns the cache as a InputStream.

You must pass this the full URL used to make the request, including the query paramters, or the hashing won’t match the saved response.

The arguments to DiskLriCache.open() must match those used internally by OkHTTP, those used by the com.squareup.okhttp.Cache.java when you issued new Cache(context.getCacheDir(), SIZE_OF_CACHE). Accordingly, when you update OkHTTP this may break - warning!

Now you must convert the InputStream to your response object:

Scanner sc = new Scanner(filterInputStream);
String str="", s;
while(sc.hasNext() && (s=sc.nextLine())!=null) {
    str = str + s;
}
ReturnType recentPosts = new Gson().fromJson(str, returnType);

The ReturnType is the type of the response, a POJO used to deserialise the JSON in this case.

android android-retrofit android-okhttp

Android: Cache network requests for offline access with Retrofit2 and OkHTTP3

Let’s first build a OKHTTP client with

  1. a cache
  2. an interceptor that checks for connectivity and if none asks for cached data:

Here’s the client.

OkHttpClient client = new OkHttpClient
  .Builder()
  .cache(new Cache(App.sApp.getCacheDir(), 10 * 1024 * 1024)) // 10 MB
  .addInterceptor(new Interceptor() {
    @Override public Response intercept(Chain chain) throws IOException {
      Request request = chain.request();
      if (App.isNetworkAvailable()) {
        request = request.newBuilder().header("Cache-Control", "public, max-age=" + 60).build();
      } else {
        request = request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 7).build();
      }
      return chain.proceed(request);
    }
  })
  .build();

We first create the cache object with 10 MB, getting the cache directory from a static Application context.

Then the Interceptor uses a utility method in my Application class to check for connectivity. If there is connectivity, we tell the request it can reuse the data for sixty seconds.

If there’s no connectivity, we ask to be given only (only-if-cached) ‘stale’ data upto 7 days ago.

Now make this OkHTTP client your client for Retrofit2 and you will be able to use your old cached data when the app goes offline.

android android-retrofit android-okhttp

Page 1 of 1