Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJava network requests and caching

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:

  1. Read cache. If it contains the data, show it;
  2. 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?

like image 897
Egor Neliuba Avatar asked Dec 01 '14 13:12

Egor Neliuba


People also ask

What are RxJava chain operators?

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.

What is the use of nextnext RxJava operator?

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.

What is the use of caching in C++?

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.

What is caching in Android?

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.


1 Answers

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.

like image 79
Egor Neliuba Avatar answered Nov 14 '22 00:11

Egor Neliuba