Advanced Retrofit2 (Part 1): Network Error Handling & Response Caching
Retrofit, most popular networking library in the recent times. The convenient thing I found in retrofit is the modularity with it’s components. It is highly customizable based on the requirement and use cases.
App uses Restful APIs to show up the content. Every activity/fragment/action may have require single/multiple API call to display/manipulate data that are keep stored in backend database. Every interaction requires network connectivity to be accomplished. Developers need to show error messages on the screen when network error occurs. Good apps cache the API response to show up the recent content when it’s running out of internet or slow in connection.
Before diving into the points of concern I would like to setup the code skeleton for this article.
This is the basic setup/configuration of OkHttp3 as a Http client for Retrofit.
Now let’s jump to the point.
My first concern is how we should handle network error? Developer’s common practice is to have a network check before each and every API call which creates boilerplate and branching in the code. I was looking for an optimal solution. Finally come up with a solution by adding an Interceptor
into okhttpClientBuilder
.
Interceptor Observes, modifies, and potentially short-circuits requests going out and the corresponding responses coming back in. Typically interceptors add, remove, or transform headers on the request or response.
Let’s progress step by step. Firstly we will create a class named NetworkConnectionInterceptor
and put an internet availability check inside the intercept(Chain chain)
method.
Now lets, initialize an object of NetworkConnectionInterceptor
and add this into okHttpClientBuilder
. Before that we will create a simple interface InternetConnectionListener
that will be used to pass the event to the listener (i.e: HomeActivity
)
Now we have our own NetworkConnectionInterceptor
that checks for internet availability on each API call. We will have to implement InternetConnectionListener
into our views (i.e: HomeActivity
). If HomeActivity
is a tabbed activity with ViewPager
+ Fragment
and if the fragments are having there own API calls, in that case we don’t need to keep checking for internet connection before the API calls. When offline, the HomeActivity
onInternetUnavailable
will be get called. We can show up the no internet UI which we can place on the top of the ViewPager
so that the content UI get invisible by the no internet UI. We can broadcast this event wherever we want by using LocalBroadcastReceiver/ RxBus/EventBus.
Full code for App
file looks like:
By this way, we will have only a single check for internet connection and we can pass the event through out the app if there is no internet. We don’t need to handle the network check place to place. Rather, in case of no internet, interface method will get called to show up the error view.
My second concern is related to response caching that rises following questions:
How can we on/off cache usage depending on network condition? What to do if we don’t want to use cache when network is available?
How to set a time limit to validate cache data if we don’t want to show up content that is older than the time frame?
Let’s have the solution step by step.
Firstly we need to implement basic cache mechanism
Now we have 10 MB of cache memory available thatOkHttp
can use to read/write API response. We can increase/decrease the memory size depending on the payload size of response. Now OkHttp
will keep caching all the response into the disk space. Let’s modify NetworkConnectionInterceptor
to handle the response with cache in terms of network state.
Here we are manipulating the ongoing request when device is offline. We are doing nothing if there is internet available. We are modifying the request only when there is no internet. The idea is, we keep caching all the response of the request that are originated by OkHttp
. But we are not pulling up the response when connected. When offline, we are adding some header information which returns the cache in offline mode. We are using max-stale= 60 * 60 * 24
that means, we are allowing the response that is cached within the past 24 Hours
from now. If the cache is older than the specified time, OkHttp
not gonna use it. More about only-if-cached
and max-stale
is here.
Wow! Now we have a cache functionality that response without an internet connection! Internet unavailability no longer means there is no content to show up. But content will be unavailable when there is no cache available (i.e: user open the app for the first time without internet or open the app after a long time when cache data become invalidate). That’s why we need a check if there is cache available for the request. And here we go, we are calling onCacheUnavailable()
if response.cacheResponse()
is null.
That’s it! We can easily manage stateful behavior with a simple OkHttp Interceptor
. We have callback for no internet and as well as no cache event. Our app can behave differently with these callback feature. We can manage behavior for a specific error response (i.e: when 401 Unauthorized/403 Forbidden occurs). I will come up with some short trick for this in later part.
Good user experience is the first priority!
Happy Coding!