Combining different sources in RxJava MVVM (FCM, Networking, ROOM) - android

I have previously used MediatorLiveData to combine results from FCM, Room and Networking in my Repository. It worked well. However, now I want more complexity and some additional bonuses from RxJava. This is why I have decided to use RxJava this time. I can combine Room and Networking with Observable.concatArrayEager(my _observables). However, I don't now how to do that after FCM pushes value, and how should I notify my main observable after new changes occur? No examples on this issue whatsoever. It is crucial part. I receive FCM in my BroadCastReceiver and then notified my repository's livedata, which notified my MediatorLiveData... How to do that with RxJava? Would really welcome any advice, because it is really important issue.

IMHO, you don't need to combine data from different sources.
Using the database as your single source of truth is definitely easier.
Room supports Flowable like:
#Query(“SELECT * FROM Users WHERE id = :userId”)
Flowable<User> getUserById(String userId);
Each time there is any updates to the table Users, Room will emit the updated user automatically once you subscribed.
The following approach may help you:
In you Activity / Fragment, subscribe to the Flowable.
Once receiving FCM notification, call network api and update the db.
Do with the updated data.
Anyway, if you need to combine sets of items from different Observables, you can use zip.

The concat operator emit the observables in the order specified, that means the second observable won't begin emitting till the first observable finish emitting objects.
But with merge operator you can combine as many observable you want into a single observable. for example:
Observable.merge(dbObservable, webObservable, fcmObservable)
.subscribe(item -> System.out.println(item));
P.S: In case you want to fetch data from a data source and keep it up-to-date using fcm you can do this:
fcmObservable
.startWith(dbObservable)
.subscribe(item -> System.out.println(item));
These are just few pattern available, as always there is nothing impossible in RxJava, based on what you want to do there is always a better RxChain for the job!

Related

Understanding reactive

Recently kotlin flow is gaining a lot of attention. I have never done any reactive programming before so i thought now is a good time to learn it. Even though I have access to books and some articles I could not understand how to integrate it say on an existing app that does not have any rxjava. I tried looking for some sample but the only thing they would give me is very basic. Im really confuse about this reactive programming thing. For example, I have a list that I needed to get on database. Why would I use flow to get that data? If I visualize it as streams, that would give me one data each. While if I get that list I could get the whole list without waiting for each streams to come if I had use flow. I read a lot of articles about this kotlin flow, even rx java. But still, I wanted to understand why streams and how is it any different from other way like the example I just gave?
For example, I have a list that I needed to get on database. Why would I use flow to get that data?
Well, that depends entirely on what you are using to access that database and how it uses Flow.
Let's suppose that you are using Room from the Android Jetpack. In that case, you can use Kotlin coroutines in two ways, via suspend functions and via Flow:
#Query("SELECT * FROM stuff")
suspend fun getStuff(): List<Stuff>
#Query("SELECT * FROM stuff")
fun getStuffNowPlusChanges(): Flow<List<Stuff>>
In both cases, Room will do the database I/O on a background thread, and you can use coroutines to get the results on your desired thread (e.g., Android's main application thread). And initially, the results will be the same: you get a List<Stuff> representing the current contents of the stuff table.
The difference is what happens when the data changes.
In the case of the suspend function, you get just the one List<Stuff> from the point when you call the function. If you change the data in the stuff table, you would need to arrange to call that function again.
However, in the case of the Flow-returning function, if you change the data in the stuff table while you still have an observer of that Flow, the observer will get a fresh List<Stuff> automatically. You do not need to manually call some function again — Room handles that for you.
You will have to decide whether that particular feature is useful to you or not. And if you are using something else for database access, you will need to see if it supports Flow and how Flow is used.

RxJava - When and why to use Observable.share()

I've seen patterns like this:
Observable<String> nameChanges = nameDataSource.changes().share();
// One subscriber
autoUnsubscribe(nameChanges.subscribe(() -> { ... }));
// Another subscriber
autoUnsubscribe(nameChanges.map(...).filter(...).subscribe(...));
// autoUnsubscribe is called when the UI is torn down
My question is:
Why is it necessary to call share() whenever I want to listen to the Observable in multiple places?
Why is not share() the default behavior for all observables?
It would be nice if the code above worked the same even without .share(). I would not have to think about when I need to share an Observable, and when I don't.
Is it for performance reasons because having a single subscriber is a special case that can be handled more efficiently?
From the docs this is not clear to me:
share() returns a new ObservableSource that multicasts (shares) the original ObservableSource. As long there is at least one Observer this ObservableSource will be subscribed and emitting data.
There are two kinds of Observables: cold and hot. Cold Observables start producing items when there is an Observer to them and they do it on an individual basis. Subscribing with multiple Observers will result in multiple runs of the same cold Observable. An example of this is an Observable that issues a network request.
In contrast, a hot Observable can produce items with or without the presence of Observers. These Observables usually multicast the same items to all of their current Observers. An example of this is an Observable of button clicks.
To turn a cold Observable into a hot one, you can use publish() which will make sure only a single subscription is established to the source Observable no matter how many Observers there are. Thus, the chain will now act as a hot multicasting Observable from the Observers' perspective.
However, often it is not economic to keep an originally cold Observable running after all Observers of publish() have gone away, therefore the refCount() operator can be used to keep track of them and stop the source when there are no interesting parties left.
If your source is already hot, you don't need share().
Why is not share() the default behavior for all observables?
Actually, this property is one of the important contributions of the modern reactive programming paradigm: the distinction of the hot and cold Observables.
However, multicasting is expensive on itself because you have to keep track of the set of current Observers in order to notify them with new events, and this can lead to all sorts of logical race conditions to be defended against. A cold Observable is known to talk only to a single Observer so there is no need for the extra tracking overhead.
I would not have to think about when I need to share an Observable, and when I don't. I'm afraid that you will have to think when programming. ;)
In the above code, yes, sharing makes sense. But what if you we're updating something on the backend, using the same network and method call from two different points, updating with different data? You would have the same call with the same Observable, but you certainly wouldn't want to share the Observable instance (and the network call) because that means that all successive calls with data would be discarded in the favour of the first one. Or if you wanted to start a timer whenever you're subscribed, you again wouldn't want to share this with other Observables.
Also, it is much easier to add certain behaviour than to remove it. For example, if sharing was the default, and the second subscriber wouldn't want to share and removes the sharing - what about the third one? Will it share it with the first one or not? At that point the sharing property becomes the property of the Subscriber and not the Observable and you would have no clear way of knowing which one is shared and which one isn't.

Tactic for several different Room queries

While refractoring an app I decided to use room (and other architecture components). Everything went well until I reached database querying, which is async. It is fine by me, I can update views with LiveData callbacks.
But the problem arose with smaller queries following each other - with no thread restrictions it was easy, you could use variables straight away.
In legacy code there are plenty of setups, where quite many small data pieces are required one after another, from different tables. E.g., querying if item exists in one table, some calculations, querying another table, etc.
Disabling async requirement for queries is not an option, I prefer using Room as intended.
First thought was to nest callbacks, but it is too ugly.
Second thought was to query for all required data, start a method only after receiving all callbacks. It also does not sound nice and there are cases where one callback has data required for the other query.
Strangely I have not found any related forum posts or articles dealing with this problem.
Did anyone handle it already? Any ideas?
Most #Dao methods are synchronous, returning their results on whatever thread you call them on. The exceptions are #Query methods with reactive return types, such as Maybe<List<Goal>> or LiveData<List<Goal>>, where the methods return the reactive type and the results are delivered asynchronously to subscribers.
So, for cases where you have more complex business logic, you have three main courses of action (that I can think of right now):
Use RxJava and try to squish all that business logic into an observable chain. There are a lot of RxJava operators, and so some combination of map(), flatMap(), switchMap(), weAreLostWhereDidWePutTheMap(), etc. might suffice.
Do the work on a background thread, mediated by a LiveData subclass, so the consumer can subscribe to the LiveData.
Use classic threading options (e.g., IntentService) or more modern replacements (e.g., JobIntentService).

Why is it not possible to map BehaviorSubject to another BehaviorSubject

At least in mobile apps BehaviorSubject is used frequently, to model a property - it has a current value, which can be queried any time, and be observed.
Sometimes it's wanted to just transform a BehaviorSubject without subscribing to it. E.g. if there's class, that acts as an intermediate layer between several transformed BehaviorSubject and potential subscribers.
The issue I have encountered here, at least with RxJava2, is that applying operators on BehaviorSubject returns always Observable. So my intermediate layer can't offer anymore an api of BehaviorSubject.
A possible solution is to create new BehaviorSubjects and subscribe them to the original BehaviorSubject but this seems a bad idea overall, maybe I don't want to subscribe at this moment but only on demand, i.e. when the users of my intermediate layer actually needs these subjects?
In my case the context is an Android app with MVVM pattern, where the view model exposes BehaviorSubject to the views, which are for the most part derived from another BehaviorSubjects in the app. I currently went with subscribing in the view model, but I would like to improve this since the view model isn't really the consumer and shouldn't be subscribing to anything - the subjects should be activated when the view actually needs something from them.
And no I can't use only Observable in the view model as there are unit tests and some other calls that check for the value at a point, which can't be done using only Observable.
My main question is why is it not possible to simply be able to transform BehaviorSubject into another BehaviorSubject. A nice to have also, what is the recommended way to work with BehaviorSubject in the described context.
It would not compose properly, operators are final methods to avoid method dispatch problems. Plus, you'd create multiple entry points for and end consumer and possibly violate the Observable contract if you's onNext the transformed subject while also onNext the original subject.
But you can have multiple subjects merged together, each driven by its own respective events and the end consumers would receive events properly.
And no I can't use only Observable in the view model as there are unit tests and some other calls that check for the value at a point, which can't be done using only Observable.
Have you tried blockingFirst() to get the current value from a chain that starts from those original BehaviorSubject?
Otherwise, your design is unclear to me as it is too much focused on subjects other than being a single originator of some events.

Rx Subscribe before Observable created

In the project, there are many modules. Each module may want to receive data emitted from other module/modules.
The problem trying to solve is, when we subscribe an observable A, this observable may have not been created yet. To solve this problem, two approaches are discussed:
Have a Observable Registry singleton. Every time when an observable is ready, put a pair into the Registry, and notify all modules that Registry changed. Each module will listen to this notification, and decide if it is a change it interested. If it is notified that the observable is ready, subscribe it. If the observable is removed, update the registry, delete corresponding pair, and notify modules, module unsubscribe it.
Rx implemented event bus. Take use of Subject: create a singleton Subject, then whenever an event or data or item need to be emitted, emit it from this subject. In your subscriber, you only subscribe on specific event, by using a filter on the subject.
The first approach looks very straightforward, and I cannot tell why it's not good. But it just doesn't look scalable to me. The second approach is the recommended way to replace otto/eventbus with Rx.
Any thoughts on these approaches?
For me the first approach is not that simple and too much to handle. The subscribers can subscribe to a topic and start receiving events whenever there is one for that topic and they would not know if there is a new event source as they don't care.
I use extended variant of version 2, which is RxHub library. It is quite flexible as allows different behavior per topic/tag.

Categories

Resources