Caching with OkHttp Interceptor and Retrofit

amitiitbhu

Amit Shekhar

Posted on September 15, 2022

Caching with OkHttp Interceptor and Retrofit

Hi, I am Amit Shekhar, Co-Founder @ Outcome School • IIT 2010-14 • I have taught and mentored many developers, and their efforts landed them high-paying tech jobs, helped many tech companies in solving their unique problems, and created many open-source libraries being used by top companies. I am passionate about sharing knowledge through open-source, blogs, and videos.

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 Outcome School.

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

Co-Founder @ Outcome School

You can connect with me on:

Read all of our blogs here.

💖 💪 🙅 🚩
amitiitbhu
Amit Shekhar

Posted on September 15, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related