Displaying Cache data or Offline mode support in android application

Kishan Maurya
MindOrks
Published in
2 min readApr 16, 2019

Problems without caching
1.
Fetching data over a network connection is an expensive operation. Sometimes due to poor network connectivity, it takes a lot of time to display result( which is a bad experience in terms of mobile application).

2. Sometimes requirement may come with offline support or to display previously fetched response when there is no internet connectivity.

Thanks to Caching mechanism. We can solve the above requirements if we cache some data.

So what is caching and how can we implement this?https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching

In my project, I have used the dagger, so I have written all the code for caching in ApiModule class. If you want to skip then directly go to below link

https://github.com/droiddevgeeks/ImageSearch/blob/master/app/src/main/java/com/example/imagesearch/di/module/ApiModule.java

How to enable cache
1. define cache memory size

int cacheSize = 10 * 1024 * 1024; // this is 10MB

2. Create a cache object ( provide application context )

@AppScope
@Provides
Cache provideCache(MyApplication context) {
Cache cache = null;
try {
cache = new Cache(new File(context.getCacheDir(), "http-cache"), cacheSize);
} catch (Exception e) {
Log.e("Cache", "Error in creating Cache!");
}

return cache;
}

Provide this cache object in OkHttpClient

@AppScope
@Provides
OkHttpClient provideOkHttpClient(MyApplication context) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.cache(provideCache(context));
return httpClient.build();
}

Now we will create 2 interceptors ( onlineInterceptor and offlineInterceptor). Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls.

https://github.com/square/okhttp/wiki/Interceptors

OnlineInterceptor which will be used when the device is connected to the network

@AppScope
@Provides
Interceptor provideOnlineInterceptor(MyApplication context) {
return chain -> {
Response response = chain.proceed(chain.request());
CacheControl cacheControl;
if (Utilities.isNetworkConnected(context)) {
cacheControl = new CacheControl.Builder().maxAge(0, TimeUnit.SECONDS).build();
} else {
cacheControl = new CacheControl.Builder()
.maxStale(7, TimeUnit.DAYS)
.build();
}

return response.newBuilder()
.removeHeader(HEADER_PRAGMA)
.removeHeader(HEADER_CACHE_CONTROL)
.header(HEADER_CACHE_CONTROL, cacheControl.toString())
.build();

};
}

OfflineInterceptor which will be used when the device is not connected to the network

@AppScope
@Provides
Interceptor provideOfflineInterceptor(MyApplication context) {
return chain -> {
Request request = chain.request();

if (!Utilities.isNetworkConnected(context)) {
CacheControl cacheControl = new CacheControl.Builder()
.maxStale(7, TimeUnit.DAYS)
.build();

request = request.newBuilder()
.removeHeader(HEADER_PRAGMA)
.removeHeader(HEADER_CACHE_CONTROL)
.cacheControl(cacheControl)
.build();
}

return chain.proceed(request);
};
}

Now its time to add cache interceptor to OkHttpClient.

@AppScope
@Provides
OkHttpClient provideOkHttpClient(MyApplication context) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.addInterceptor(provideOfflineCacheInterceptor(context))
.addNetworkInterceptor(provideCacheInterceptor(context))
.cache(provideCache(context));
return httpClient.build();
}

Finally, add OkHttpClient to Retrofit

@AppScope
@Provides
Retrofit provideRetrofit(OkHttpClient client,Gson gson) {
return new Retrofit.Builder().baseUrl(ApiConstants.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build();
}

Using this retrofit instance, we can make an API call and the caching mechanism will work.

Few points to remember

Photo by Kelly Sikkema on Unsplash

Soon I will post more articles on android, core java.
till then happy learning… :)

--

--