Loading data from multiple source with Error Handling — Cache + Remote
TL;DR: RxJava concat operator helps combine output of two or more observable sources and maintains the sequential order of execution without interleaving the emissions.
Most often than not, we always want to serve our users with the latest data from the server. But networks calls can be slow depending on our users connectivity, this may cause user to see progress dialogs for a long time or even a blank screen. As such we should alway cache data for use offline. But what happens when the user comes back online?
An efficient setup to make sure our user is always served with the latest possible data at any time would be :
1. Serve user cached data if any exists.
2. Retrieve fresh data from remote server as quickly as possible, save in cache and serve data to user.
Basic Setup
Given an Observable<Data>
for each data source (network, cache), we can construct a simple solution the concat operator. The concat operator combines the output of two or more observable sources and maintains the sequential execution without interleaving the emissions.
This setup always emits data from cache first, it then fetches data from the server and then emits that data.
It is important to note that the order of the observables matter as it the concat operator checks them one by one.
Handling Error — Making concat work for you
If we run this code at first setup, we will likely get as error. Why? — Because mostly at first setup our cache has no data, so if it tries fetching from there it may throw an error.
Any time an error is propagated by any of the observables in the concat operator, other observables in the chain will not be called. So we have to manually help the concat operator to continue execution despite any error that occurred. The onErrorResumeNext() operator will do the work just right.
Here we first try fetching data from the cache, our onErrorResumeNext() operator returns an empty observable using Observable.empty() operator, this makes the concat operator ignore any error thrown from the cache and continues to the server to fetch data.
Now while fetching data from the server if any error occurred, its important to check if our cache has any data. If our cache doesn’t have any data, we can emit that error else we ignore the error and continue with data served from the cache.
Recommendations
Although this solution is simple and efficient, in a modern approach to this we can make our database a single source of truth and every data obtained from the server is saved to the database and then emitted from there.