Android Pros & Cons: Event Bus and RxJava - android

I have been using Event Bus in my apps (i.e: greenrobot/EventBus). But I find some disadvantages in using Event Bus:
Chaining tasks execution is difficult
A lot of classes to represent events
Less clear code (well, it's still possible to trace, but not as clear)
I have been researching for new techniques to deal with this problem. And I read quite a bit about RxJava and wonder if it could be a solution.
So my questions about RxJava (based on what I have read recently):
Could RxJava observer be registered at any time? So not just when creating the Observable. With EventBus this is possible, I could subscribe at any time, not just when the Observable is created.
How do you handle two or more publishers publishing the same type of event (e.g: navigation event)?
Tightly coupling the publisher(s) and the subscriber, means that I have to explicitly specify the publisher(s) every time. So I have to worry not just with the type of events, but also the originators. With EventBus, I only need to worry about the type of events and not the originators.

1) Once you have an instance of an Observable, you can subscribe to it at any time and from any thread, even concurrently.
2) We usually merge the streams of multiple observables via Observable.merge() or use a serialized PublishSubject.
3) If you observe an Observable, there could be dozens of upstream operators and sources involved, but you'll get a sequential stream of values no matter what. You only need to get a hold onto an Observable representing some source of events and the observer doesn't need to know if the event was merged, filtered, made a roundtrip over the network and got delayed before arriving in your onNext() method. You can naturally implement or use some lookup service that will get you an Observable to reduce the coupling, but with RxJava, coupling is not usually an issue.

Related

channel or mutablesharedflow , which one is a better replacement for deprecated localbroadcastmanager

In the past, I was using LocalBroadcastManager and EventBus in my chat and taxicab applications which are now either deprecated or not recommended using them.
I intend to replace them with new data structures like mutablesharedflow or channel,
i want to know which one is better matched with my case? or maybe another data structure?
From Roman Elizarov, Channels were added as an inter-coroutine communication primitive.
You cannot use channels to distribute events or state updates in a way that allows multiple subscribers to independently receive and react upon them.
So they introduced Flow. But Flow is a cold observable, where every subscriber gets their own data (independent from other subscribers). With SharedFlow you get a hot observable that emits independently of having any subscriber(s).
You could do the same with ConflatedBroadcastChannel. But JetBrains recommend to use Flow in favor of Channels because of their simpler API.
So if you want to migrate to Coroutines and you need a hot observable multiple subscribers can listen to, you should go with SharedFlow.
Both are good for listening one time events. Everything depends in your use cases.
SharedFlow known as hot flow ->
Emit events even if no observer is listening to it
If no observer is listening to it, you loose these events
Channels known as cold flow
Does not emit events when no observer is not listening to it. It works like a BlockingQueue.
When you start to collect, it collects all data which were sent.

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.

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.

What is the difference between EventBus and RxJava? [duplicate]

This question already has an answer here:
Android Pros & Cons: Event Bus and RxJava
(1 answer)
Closed 3 years ago.
I am confused about the difference between EventBus and RxJava in android. I need to implement one of them for my issue about notifying some components when some changes have been done, so that they can update their state.
Also, I read that EventsBus has became deprecated over RxJava and I don't know if this information is true or not.
EventBus and RxJava are different in their nature.
EventBus is just a bus as the name suggest - it provides the mechanism to subscribe and publish events to the "bus", without you caring how the wiring is done, what this "bus" actually is, etc. In the context of Android, the EventBus is just an easier way to deal with sending and receiving Broadcast messages with less boilerplate.
RxJava on the other hand is much much more powerful than that. Yes, you can subscribe and publish events, but you have far more control over the process - frequency, on which thread everything happens, etc. The main power of RxJava (in my opinion) is that you can manipulate the data being published very easy, using some of its tons of operators.
To sum up - if you only care about publishing some events and performing some actions when received - you'd probably be better off using the simplest of the two, namely some kind of Bus, or even plain old BroadcastReceivers. If you will also benefit of transforming the data, handling threading or simplified error handling - go for the RxJava approach. Just keep in mind that RxJava generally has a steep learning curve, so it takes some time to get used to its concept.
To understand RxJava, think of a list. Today manipulating a list like transforming, splitting, merging can be done easily using functional methods (map, groupBy, etc). RxJava uses the same principles except that its main target is not list but stream. Stream is asynchronous, often live data such as websocket channel or online movie.
Event bus comes from the needs to decouple classes which in Android are often bound with life cycle. Tight coupling of network callback and Activity's Views as an instance, has been a cause of numerous null pointer exceptions. Event bus with its publisher-subscriber pattern alleviates this issue.
How does it get mixed with RxJava ?
To begin RxJava incorporates Observable pattern. Here an Observer watches an Observable and reacts when an event arrives. Observable has several sub-classes, among which is Subject that has the properties of both Observable and Observer. Since it works by trapping an event and publishing it to subscribers, it technically functions as event bus.
Is it wise to use RxJava as event bus ? No. RxJava would introduce unnecessary complexities for simpler purposes. Only use it if the app does manipulate streams. For example pairing frames from a movie stream and subtitles from another stream. If the app simply consumes a REST API and needs to decouple the callback from activities/fragments then event bus is enough.
Live #Vesko wrote, RxJava and event bus differ in their nature and may serve to solve different problems. Nevertheless, there are some scenarios in which both of them can solve the same problem (although at different costs), and this might be the reason for why many people confuse these two concepts.
RxJava is conceptualy similar to Android LiveData that was released not so long ago, and to better understand these concepts, as well as event bus, I suggest you read my post. In the post I go over these very concepts, describing the scenarios in which we should use one over another and the pros and cons of using one rather than the other. I think it may be useful to you:
When and why to use LiveData
If you want to fetch data from sever and update UI, use RxJava + Refrofit. If update UI or do some operation without fetching data, EventBus is enough.

Categories

Resources