DEV Community

Cover image for Caching with OkHttp Interceptor and Retrofit
Amit Shekhar
Amit Shekhar

Posted on • Originally published at amitshekhar.me

Caching with OkHttp Interceptor and Retrofit

I am Amit Shekhar, a mentor helping developers in getting high-paying tech jobs.

In this blog, we are going to learn how to cache HTTP responses in Android using OkHttp Interceptor and Retrofit for building offline-first Android apps.

This article was originally published at amitshekhar.me.

Let's understand how caching is going to help us in our Android applications.

  • When we make a network call to fetch the data from the server.
  • For the very first time, it will get the data from the server and it will cache the HTTP response on the client.
  • Then, if we make the same API call again, it will return the data from the cache instantly.

This way, our Android applications can do two very important things:

  • Work even if there is no internet connection. This will helps us in building the offline-first apps.
  • Work faster as the response is cached locally.

Now, let's learn how to enable caching in OkHttp and Retrofit. Before that, we need to understand that Retrofit uses the OkHttp client for HTTP operations, which means that whatever we have to do to enable caching, we need to do with the OkHttp. We do not have to do anything extra for Retrofit as it will use our configured OkHttp client.

Things become easier when we already have the Cache-Control header enabled from the server, then OkHttp will respect that header and cache the response for a specific time that is being sent from the server.

But what if the Cache-Control is not enabled from the server? We can still cache the response from OkHttp Client using Interceptor. We will learn how.

For this, we need to implement Interceptor like below:

class CacheInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val response: Response = chain.proceed(chain.request())
        val cacheControl = CacheControl.Builder()
            .maxAge(10, TimeUnit.DAYS)
            .build()
        return response.newBuilder()
            .header("Cache-Control", cacheControl.toString())
            .build()
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, we created CacheInterceptor by implementing Interceptor and we have a CacheControl builder that is used to provide the header for the Cache-Control.

Then, we need to add this CacheInterceptor to the OkHttpClient using addNetworkInterceptor.

val okHttpClient = OkHttpClient().newBuilder() 
.addNetworkInterceptor(CacheInterceptor())
.build();
Enter fullscreen mode Exit fullscreen mode

After that, we can use this okHttpClient directly or with Retrofit.

But, there is a catch that we need to understand while building the offline-first app.

OkHttp is designed in such a way that it returns the cached response only when the Internet is available.

  • It returns the data from the cache only when the Internet is available and the data is cached.
  • It returns with the error "no internet available" even when the data is cached and but the Internet is not available.

How to solve this issue?

We can create a ForceCacheInterceptor in addition to the above one (CacheInterceptor, only if Cache-Control header is not enabled from the server).

class ForceCacheInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val builder: Request.Builder = chain.request().newBuilder()
        if (!IsInternetAvailable()) {
            builder.cacheControl(CacheControl.FORCE_CACHE);
        }
        return chain.proceed(builder.build());
    }
}
Enter fullscreen mode Exit fullscreen mode

Then, add the interceptor in OkHttpClient like below:

val okHttpClient = OkHttpClient().newBuilder()
.addNetworkInterceptor(CacheInterceptor()) // only if Cache-Control header is not enabled from the server
.addInterceptor(ForceCacheInterceptor())
.build();
Enter fullscreen mode Exit fullscreen mode

Here, we need to notice that we are adding ForceCacheInterceptor to OkHttpClient using addInterceptor() and not addNetworkInterceptor().

  • addInterceptor: used to add the interceptor at the application level.
  • addNetworkInterceptor: As the name says, used to add the interceptor at the network level.

After that, we can use this okHttpClient directly or with Retrofit and it will work as expected.

This is how we can cache HTTP responses in Android using OkHttp Interceptor and Retrofit for building offline-first Android apps.

That's it for now.

Thanks

Amit Shekhar

You can connect with me on:

Top comments (1)

Collapse
 
ardakazanci profile image
Arda Kazancı

Thanks for your nice article. So how do we confirm that it has been retrieved from the cache?