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.
Related
I'm working on this project in Android in which an aspect requires a CountdownTimer with a foreground service. A few other answers on Stack Overflow mentioned that LocalBroadcastManager would be suitable for my needs.
The documentation in Android Developers, however, mentions that it has been deprecated. Any suggestions on what I should use in its place? The documentation mentioned about using LiveData, but I was wondering if there are any easier alternatives.
LocalBroadcastManager is basically an event bus with a lot of unnecessary ceremony around Intents and intent filters. So one replacement is easy, and functions quite similarly: you can use any event bus library. greenrobot's EventBus is a popular choice (here's a guide for it) and Guava also has one, if you're already using Guava (but Guava is pretty heavy to include just for an event bus).
But event buses suffer from the same problems that LocalBroadcastManager does that led to it being deprecated: it's global, it's not lifecycle-aware, and as your app gets larger, it becomes much more difficult to reason about the effects of a change to an event. For cases of observing data, LiveData solves this quite nicely because it's lifecycle-aware, so you won't get change notifications at the wrong time (like before your View is set up, or after onSaveInstanceState) - but it'll handle delivering the change notifications when you're in the right state again. It's also more tightly scoped - each piece of LiveData is accessed separately rather than having (typically) one event bus/LocalBroadcastManager for the entire app.
For cases where it's more of an event rather than a piece of data being changed, you can sometimes convert it to a piece of data. Consider if you have "login" and "logout" events - you could instead create a LiveData that stores an Account for logged-in users, and becomes null when the user is logged out. Components could then observe that.
There are certainly cases where it really is difficult to convert it to a piece of observable data (though I can't immediately think of any examples that would typically be used with an event bus patten). For those, consider writing your own listener interface, similar to how on-click listeners work.
For your example of a countdown timer, I think LiveData is a pretty straightforward solution, and will be much easier than an event bus or even LocalBroadcastManager would be. You can just have a LiveData of the timer's current value, and subscribe to it from whatever needs to show the value.
When using Firebase Cloud Messaging on Android, it is often desirable to notify the current Activity of an incoming push notification. One of the recommended ways to do this has been to use LocalBroadcastManager to send an Intent from the FirebaseMessagingService implementation to the Activity (StackOverflow example answer).
However, as of version 1.1.0-alpha01 (2018-12-17), LocalBroadcastManager is deprecated:
LocalBroadcastManager is an application-wide event bus and embraces layer violations in your app: any component may listen events from any other. You can replace usage of LocalBroadcastManager with other implementation of observable pattern, depending on your usecase suitable options may be LiveData or reactive streams.
While it is highly likely that this class will remain available for a while longer, I would like to start cleaning up our applications anyway, so I want to migrate to something better before Google actually removes the old way.
Right now, there are two main roles that these local broadcasts have in our apps:
Update the UI with the new data from the push notification. The way this worked was that each Activity that cares about the incoming push data has a broadcast receiver that listens for the appropriate message and updates its own view data.
Force the user to log out if the server sends a notification to end the session. This works with each activity having an instance of a broadcast receiver that listens for a logout event, ends the Activity, and starts the Login Activity.
As I see it, these use-cases have issues with both of their suggested alternatives:
LiveData is easiest to use in an Activity or Fragment as part of a ViewModel. However, ViewModel is only meant to be used from those classes that directly deal with the UI. Accessing the ViewModel from within the FirebaseMessagingService takes an ugly hack and is a really bad idea from an architectural perspective. Also, different activities and fragments have different ViewModel objects, and I don't want the service to need to access them all.
I can create a Kotlin object (a.k.a. Singleton) with a bunch of LiveData properties, have the FirebaseMessagingService update those LiveData objects from the incoming messages, and have the Activity observe those changes and copy them into its own ViewModel's LiveData properties. The problem with that is twofold: first, it requires me to have two identical LiveData objects for each piece of data, one in the ViewModel and one in the object; and second, it doesn't help me with handling the "log out event", because LiveData is meant to handle changing data, not listening to a stream of events. (I may be able to handle the second issue using this LiveData Event Wrapper, but that still feels like a bad hack over something that isn't meant to work this way.)
While reactive streams, such as RxJava, will probably do what I need, I already forced my team to learn Kotlin, Android Databinding, Android ViewModel, and a bunch of other new stuff in the last few months, and I don't think they can take much more. RxJava is also a large thing to add for just this one use, and we have no plans to rewrite the entire application to take advantage of it in order to justify its addition.
One suggestion I found was to use Kotlin Coroutines with Channels or Flows. These can be used very similar to reactive streams, but (unlike RxJava) are intended to be used with Kotlin and benefit from Kotlin's improvements over Java. This option is especially attractive now that Google has announced that they are focusing on Kotlin for Android development instead of Java.
While this seems to me to be the best option, I have not managed to find any feedback from others about whether it works and if there are side-effects and/or pitfalls to such an implementation. The only thing I found was an open issue on the kotlinx.coroutines repository about the need for providing an example of an application like this. While I'd love to contribute such an example, I don't think I know enough about it to create a good example, and I don't want my production apps to be the guinea pig. I also don't know whether it is better (or proper) to use explicit couroutines with Channel or to use suspend with Flow for this case.
In summary:
Are Kotlin Coroutines and their associated concurrency structures a good way to handle communication between Android Service and Activity?
If yes, which Kotlin type makes more sense to use, Channel or Flow?
Coroutines don't really help with the handoff of data from one software component to another. They help with the processing multiple units of asynchronous work using syntax that appears as if they were synchronous. That's the bottom line for coroutines. They're analogous to async/await syntax in JavaScript. While you might use a coroutine to access data from asynchronous sources, it doesn't give you any primitves to proxy that data on to other components.
LiveData probably works just fine for what you're trying to do. Don't conflate ViewModel with LiveData - they solve different problems. While you're correct that ViewModel should only be accessed by code that deals with UI, that guideline doesn't extend to LiveData. It's perfectly reasonable to expose a LiveData that reflects current data from FirebaseMessagingService that is later picked up by a ViewModel, transformed, and passed on to a view. This LiveData could be a singleton, or obtained via whatever dependency injection infrastructure you choose.
Bear in mind that LiveData is really only supposed to be used for managing changes in state. It's not a "stream" of data that your app can listen to. You will need to make sure that your infrastructure is state-based in order for this to work out well. FCM itself is not state-based, but if you want your views to respond to messages from FCM, you'll need to retain enough context between each message to make sure your UI responds consistently to new messages (or the lack of messages altogether).
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).
Can I use the Event Bus to decouple all of the application layers? I m trying to use the clean architecture. Normally the decoupling is made by a boundaries interfaces, I have seen some examples using RX observers for that. The question is can i use Event Bus to decouple the layers? and can the event bus handle such a job?
Event Bus is perfect for cross-cutting activities so you don't need to pass trough a middle layer to deliver an event if you don't need to.
For clean/onion/multi-layer architecture you don't need Event Bus but clear contracts between the layers i.e. boundary interfaces. They may or may not use RX.
You can fully decouple modules using on Event Bus with no interfaces whatsoever and then all components will be extremely decoupled, however it will become a hell to debug, maintain and super difficult to do anything meaningful :) So some kind of contract is always a good idea even when using Event Bus.
Combining Reactive Programming and Event Bus you can create highly decoupled event driven pico services bounded by some contracts around your Event Bus in order to improve clarity of the event/command/data flow.
I am personally using and working on RxHub which was born exactly from the need of passing cross-cutting events and easy data-flow operators chaining.
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.