I am seeking an example of a flow I'm trying to implement with help of RxJava.
Suppose I want to show a list of data. The flow should look something like this:
Send an API request to the server:
If it returned the data, then cache it and show it.
If it returned and error and there was no cached data, then show an error.
If it returned and error and there was something cached, then do nothing.
Right now I have a method that does something similar (with lots of inspiration from Jake's u2020). The main difference is that it uses in-memory caching, which means there's no need for a separate Observable
for reading from cache and it can be done synchronously.
I don't know how to combine two observables (one for reading from cache and the other for API call) and obtain the flow described above.
Any suggestions?
In RxJava, there are hundreds of operators to choose from. The majority of operators act on an Observable and return another Observable. This allows you to apply these operators in a chain, one after the other.
Next Rxjava operator is firstElement, this operator will make sure if we get the data from memory, it will not let the other observables (disk, network) do anything or if we get the data from the disk, it will not let the network observable do anything. So, this way no redundant work at all.
Caching is very useful in the following situations: Reduce network calls: We can reduce the network calls by caching the network response. Fetch the data very fast: We can fetch the data very fast if it is cached. Memory Cache: It keeps the data in the memory of the application.
Understanding Caching in Android. When the user launches the program for the first time, there will be no data in memory and no data in the disc cache. As a result, the application will need to make a network call to retrieve the data. It will retrieve data from the network, store it to disc, retain it in-memory cache, and then return the data.
I think I solved my problem. The observable chain looks like so:
apiCall()
.map(data -> dataInMemory = data)
.onErrorResumeNext(t -> data == null ?
Observable.just(Data.empty()) : Observable.empty())
.startWith(readDataFromCache().map(data -> dataInMemory = data))
.subscribeOn(ioScheduler)
.observeOn(uiScheduler)
.subscribe(dataRequest);
The main point is, that if readDataFromCache()
throws an error, it will call onCompleted()
without calling onError()
. So it should be a custom Observable
which you can control.
Data.empty()
is a stub for my data - the Subscriber
should treat it as an error.
dataInMemory
is a member in my controller which acts as in-memory cache.
EDIT: the solution doesn't work properly. The completion of one use case (see comment) is not achieved.
EDIT 2: well, the solution does work properly after some tweaking. The fix was returning different types of observables depending on the state of in-memory cache. Kind of dirty.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With