I would like to describe how the communication in my app works in the hopes that someone can tell me if it's good/bad/just okay design.
My app is single Activity multiple Fragments. The Activity has several generic functions such as show/hide a Progressbar animation on the screen or showing a Snackbar. This is functionality that should only be implemented in one place.
My Fragments send broadcasts whenever they need functionality that is not in the Fragment. For example, if the Fragment wanted to show a Snackbar message, I would send a broadcast like this:
localBroadcastManager.sendBroadcast(new SnackBarIntent("Show this text"));
The Activity receives this broadcast, and shows the Snackbar message. Of course, this is a one way message. My Fragment doesn't know if the broadcast was received. But all in all, it works. I can send broadcasts from anywhere, a Service, an Adapter, etc. I can also send Broadcasts between Fragments if I wanted.
I understand there are alternatives to this. There is an EventBus. Or I could pass a reference of the Activity into the Fragment, Adapter, etc. To me this sounds like a terrible idea that could prevent proper garbage collection.
Then there is RxJava where I guess my fragment subscribes to an Observable that I get from the Activity.
But the question remains, is it bad to use BroadcastReceiver in this way? And if so, why?
Is it wrong? No, they were meant for things like this. I'd make sure I was using a local broadcast and not a global one, for efficiency. Some of the alternatives may provide a nicer API or more features, but they all do more or less the same thing.
I would say that unless the part of the code that broadcasts is really buried that you're better off with interfaces and method calls than broadcasts. The problem with any kind of event broadcast is that it decouples the sender and receiver. That can have advantages when you'd otherwise need to pass objects through multiple levels or to places that shouldn't know about that part of the system. But it has drawbacks in maintenance, especially if multiple places can put similar messages on the same bus.
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.
There are lot of threads about how to make two Fragments communicate each other using an interface and event call back methods through Activity.
Is there any specific reason to do that way? or is there any downside doing this way-directly calling method of fragment-2 from fragment-1
((Fragment2) (getActivity().getFragmentManager().findFragmentById(R.id.fragment2))).methodOfFragment2();
Unfortunately the activity-interface in many tutorials doesn't give people a good model for actually making their fragments modular.
What most people end up doing is making their activity-interface some central repository for hardcoding relationships between fragements. Thus, when I first started usnig fragments and read about this "model" I too wondered at its value, since I was just introducing a layer of indirection over my fragment relations.
overtime I learned or adapted patterns, like the Broadcast/Receiver model to my fragments. Now my fragments don't communicate through the activity-inteface, but instead broadcast events on an event-frequency with payloads through a local broadcast object, and other objects interested in those events can register to receive those events and data.
In other words, my fragments have events, and they publish those events, often with payloads, and other objects can register to receive notification and data from those events. If no one's listening, nothing happens. If I write some new object that want's to receive data from the event, my other fragments and even my broadcaster don't need to be aware of any specifics of how my new object was implemented.
If you want to learn more about the broadcast Receiver model Android has its own LocalBroadcastManger, or you can write your own lightweight one, and you can find some tutorials on how to use it here:
http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html
how to use LocalBroadcastManager?
Because a fragment is suppose to be able to be reused. If you are calling a fragment that exists in one instance of your app and you reuse one of those fragments in another section of your app but not the other then guess what you just broke your app trying to call something that is not there.
Fragments should not know another fragment exists which is why all communication should go through an activity
I have a class called FlashlightFragment that allows the user to control the flashlight.
The problem is that the user can turn the flashlight on or off from a number of places. Since all changes to the flashlight pass through a class called FlashlightHelper I want to broadcast a message from it that can be received anywhere on my app. I remember there was a way to do this but I cannot remember the name of the feature.
Basically I want to send a message like: "FLASH_ON" from FlashlightHelper and then set listeners on different fragments and activities on my app that can receive this message.
How is this done?
I won't specialize to the specific situation that you face but instead answer the question in general: How to send a message from one class to another (or to many others).
BroadcastReceiver
Intents and Intent filters
... These are the main methods that will probably be enough for you. Then there are software engineering patterns such as The singleton pattern that will do the trick, but I ll stick to the first to If I were you.
i'm trying to call a method in my main activity via a button of a widget.
the widget has different buttons with different values. i want the method to do its job without showing up the gui attached to the main activity. (send http request with button value)
so far i searched for some tutorials but i didn't quite understand them, my code got all clumsy and it barely worked. i think a mix of intents, services and broadcasts are needed to realize this?! i really don't know, can somebody post a understandable description or tutorial which covers all aspects of how to do this?
i think there is no code or pictures to provide because there is nothing look at right now.
thanks in advance for any answer.
Android AppWidgets don't need to have any relation at all to an Activity, although it is certainly possible to have a click or something start an activity.
As you probably know, the primary interface to AppWidgets is through your AppWidgetProvider (if you don't know what any of this is about, take a look at the official android guide).
You can tell a button to use a PendingIntent to do one of several things when clicked:
To start a service (probably your best option for time consuming tasks like http requests), using PendingIntent.getService.
To start an activity, use PendingIntent.getActivity.
To broadcast a message to a BroadcastReceiver, create it using PendingIntent.getBroadcast.
In all of these cases, you would tell the button to run the PendingIntent with the
setOnClickPendingIntent(int id, PendingIntent operation) method of RemoteViews.
The Intent you pass to any of these methods should typically be created using the Intent(Context, Class) constructor, where the second argument is the service, activity or receiver class you want the pending intent to be sent to.
I am developing an application which has around 8 Activities, and a class which is used to connect/receive data to/from an embedded Bluetooth chip. When I started, a Bluetooth object was initialized in my initial Activity, where there was a Handler which received messages from the Bluetooth object.
After poking around on the internet for a while, it seems like the best idea for me is to turn my class into an Application subclass. However, doing this removes the need for me to initialize an object in the MainMenu, which removes my ability to pass it the Handler used.
Does anyone know of a way to eliminate the need for a Handler, so that every time the Bluetooth Application changes it state or receives data, the current Activity can access it?
My main problem with this approach is that the Activity doesn't know when the Bluetooth Application will be sending it messages, the Application waits and listens, and then notifies the Activity when it happens.
OR
Is it bad practice for me to write the Handler into the MainMenu, have it handle messages for ALL the different activities, and then pass the Handler from Activity to Activity?
I'm going to assume that you're trying to achieve the following as it's a little unclear from your question your ultimate aim (sorry!):
Your application has several activities but only one Activity receives the data from the bluetooth device.
The other activities in in your application require the data from the bluetooth device but are not receiving it directly from the bluetooth device. Currently you're providing the data via the one activity mentioned above.
You want to NOT use a Handler to achieve this.
If my above assumptions are correct then you are going along the correct lines but you probably do not want to use a Handler.
You are quite correct in having one Activity handle all the interactions with the Bluetooth device. It simplifies things and provides a much better, cleaner way of handling the Bluetooth device. However you need to get the data from this one Activity to all the others and to achieve this you would probably want to use Broadcasts, BroadcastReceivers and Intents. See here for an overview.
However if you can you might want to take a look at using LocalBroadcastManager as this keeps any broadcasts within your own app's space. Broadcasts are global and should be avoided if you do not need to pass the data outside of your own app due to security implications.
Finally, have you considered using Fragments for your other Activities? Another disadvantage with Broadcasts is there is extra overhead associated with them. If you're keeping data within your app then you can create an interface to be implemented by each of your Fragments and your main activity just calls that interface on the Fragment that is currently selected.
You can use BroadcastReceiver class to send broadcast messages to your activities. see here http://developer.android.com/reference/android/content/BroadcastReceiver.html
When you get the data you need into the application class, you can send it to the activity you want.. just make sure that the activity has registered to receive that broadcast message..