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.
Related
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).
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.
A library that I am using has an Android activity. I would like to pass a callback to the activity to get notified of certain user events like when user enters a specific code or draws something on the screen. I am not able to find a way to pass callbacks to the android activity.
Note: I can edit the library, however, I prefer to leave the activity within the library for architectural reasons and ease of testing without integrating with the larger app.
What is the best possible way to solve this? Are there any Android design patterns?
What is the best possible way to solve this?
Modify the activity to post an event on an event bus (greenrobot's EventBus, Square's Otto, LocalBroadcastManager when these things occur. Then, listen for those events elsewhere in your app.
I prefer to leave the activity within the library for architectural reasons and ease of testing without integrating with the larger app
Then convince the developer of the library to modify the activity to post an event on an event bus (greenrobot's EventBus, Square's Otto, LocalBroadcastManager when these things occur. Then, listen for those events elsewhere in your app.
Or, convince the developer to offer some other means of accomplishing this (e.g., you subclass the activity and override certain methods to be notified of these events).
It sounds like you have access to the library src code, so create an AIDL interface for communication between your app and the lib. You can set up a callback via AIDL and have the lib send your app the data in real-time as it gets generated.
There's quite a bit of code involved but it is achievable. You can start here:
https://developer.android.com/guide/components/aidl
I have many Activities which raise background tasks; the Activities will pass themselves in as having implemented a listener callback, so that the background tasks can raise an event on the Activities. The Activities in turn can show something on the UI to indicate that a background activity passed or failed.
Alternatively, I could use an EventBus, wherein I get the Activity to register itself as a listener/subscriber. I can have a background tasks raise an event on the EventBus and the Activity listening to it can handle it.
What are the advantages of one over the other? When would you use one over the other? (Code cleanliness? Performance? Caveats?)
Follow up - I did end up using EventBus. The code is definitely a lot cleaner and there aren't callbacks hanging out everywhere. The IDE (IntelliJ) thinks that the onEvent methods are unused, so I created an annotation
#Target({ElementType.METHOD})
public #interface EventBusHook {}
and placed it over my onEvent methods. Then Alt+Clicked on it and asked IntelliJ to not treat it as unused.
#EventBusHook
public void onEvent(MyEventType myEventType){
I disagree with #nnuneoi's answer.
Event bus has just one single advantage: it allows for communication between components which are "unaware" of each other's existence.
And there are several disadvantages:
The components become loosely coupled by dependency on both event bus and specific event type
The coupling described in #1 above is not strong
The coupling described in #1 above is not evident
Event bus introduces performance overhead over simple callbacks
If event bus holds a strong reference to subscribers (as is the case with e.g. GreenRobot's EventBus), then unregistered subscribers will cause memory leaks
Given all these disadvantages, simple callbacks should be the default implementation choice.
Event bus should be used only when direct coupling is not desired or hard to implement. For example:
Sending events from Service to Activity
Exchanging events between independent Fragments
Application wide events (e.g. user login/logout)
If the communicating components are already "aware" of each other's existence, there is no need for them communicating via event bus.
Benefits of using EventBus:
Your code will look much more clean
Your code will become more modular which will allow you to easily create test case for your code
Avoid memory leaks from bad object references which lock the object and does not allow Garbage Collector to clean it up
Could have more than one receiver a time, that it much like broadcasting
Simplify multiple interfaces into a single one, EventBus
In an interface class, you need to override every single method in the class that is inherited. With EventBus, you can listen for just an event that you really want
But bad part is you might be a little bit more headache with the function declaration since IDE couldn't help you with auto-complete.
My suggestion is, if you find that you have to create a custom listener, then please consider EventBus, it might be a better choice for most of (if not all) of your requirements/cases.
Anyway, it is all your choice after all =)
You should check if your event is globally unique on the semantic view. Either an subscriber is interested in the event or not. If not he shouldn't subscribe.
Event-Bus mechanism is right if you really have a publisher-subscriber relationship. The event must be totally independent of the receiver.
So a subscriber that discard the event for any reason of responsibility ("I am not responsible the event even if I am registered") is a strong indicator that using an Event-Bus is wrong. Then you should consider using dedicated listeners.
I would go with the EventBus because of the loose coupling and cleaner code. Also, the fact that using an EventBus such as Greenrobot automatically does all the boilerplate for me and allows me to register & deregister observers right from Activity Lifecycle methods (onStart and onDestroy|onStop) is great. Implementing callbacks and still managing to control Activity lifecycle management for those callbacks is an unnecessary headache and involves a lot of unnecessary boilerplate.
Also, apparently all garbage collectors think weak reference is great-Event bus gives your observers and components exactly that. Its the basis of the Observer pattern.
Is it good practice to use Otto event bus bi-directionally?
I mean, send events from controller to view, and view to controller?
Or is it just meant to publish results meaning its purpose is only events from controller to view?
Thanks
Good question. Here is my thoughts on this. I use Otto for a while and use it bi-directionally. From my experience there is nothing against doing this. I have just defined couple of rules helping me keep everything under control.
One-to-many pattern must be confirmed. I mean here, that one producer should normally notify multiple subscribers. Of course, at different point in time there can be zero or more subscribers. But if you have a case, where by-design maximum number of subscribers is just one, then you trying to dispatch rather a "command", than an "event". For such cases I would use a direct call instead of posting a event.
Another thing to avoid should be a situation, when one event triggers another event, which, in turn, triggers first event again. You can run in infinite event chain here. This might happen when same class has the both subscriber and producer methods. If I have such classes, I try to keep those methods as independent as possible.
And of course I always use Android components' lifecycle to register and unregister publishers and subscribers dynamically. I start with onResume() and onPause() methods and, if needed, I'm going up to onStart() or even onCreate().