Receiving a broadcast during Activity's lifecycle changes - android

Let's say I have an Activity. In its onCreate lifecycle callback I create a BroadcastReceiver object by implementing it as an anonymous class and put some code inside its onReceive callback that requires Activity's Context to show a Toast message when it gets called. In Activity's onResume callback I register that BroadcastReceiver and in onPause I unregister it, because it contains code that requires Activity's Context, and it might not be available if Activity is going through the destruction procedure, i.e. orientation change. This means that if something, i.e. IntentService broadcasts an Intent for that BroadcastReceiver while it's unregistered (no matter how short, but it still can happen), the Intent will never get delivered and proper actions that handle it will never happen. So the user might miss some important information (message informing about a succesfull registration, warning that something went wrong etc.) Am I right? Is it true that such scenario may happen? How to prevent it? How to make sure that the BroadcastReceiver will receive the broadcast no matter when some part of the application fires it?

Create MyBroadcastReceiver extending BroadcastReceiver (of course :D) and register that in the manifest with the appropriate intent filter action. Then in onReceive() you'll have access to Application's Context. Keep in mind that onReceive() will be triggered even if your app is closed (if your action is Intent.ACTION_SCREEN_OFF for example).
It depends on what you're trying to do in that receiver...also have a look at EventBus https://github.com/greenrobot/EventBus if you have to send events in your app.

Related

How to receive message when activity is inactive?

I'm using BroadcastReceiver in activity to receive message from others services. It works well, but the problem is that
When my app goes to the background, the BroadcastReceiver will be unregister from the activity. so the messages which are received before the activity go to front will be lost.
How to handle the case?
Scenario A: Only The Activity
If you only need to receive the broadcast when you have an activity in the foreground, have the activity register the BroadcastReceiver using registerReceiver(). As #MisterSquonk indicated, you would register the receiver in onResume() and unregister it in onPause().
Scenario B: Activity If In Foreground, Else Other; Ordered Broadcast
If you want the foreground activity to handle the broadcast, but you want something else to happen if that activity is not in the foreground (e.g., raise a Notification), and the broadcast is an ordered broadcast (e.g., incoming SMS), then you would still use the Scenario A solution, but with a higher-priority IntentFilter (see setPriority()). In addition, you would register a BroadcastReceiver via a element in the manifest, with a lower-priority for the same broadcast. In the activity's BroadcastReceiver, call abortBroadcast() to consume the event and prevent it from reaching your manifest-registered BroadcastReceiver.
Scenario C: Activity If In Foreground, Else Other; Regular Broadcast
If Scenario B almost fits, but the broadcast you are listening for is not an ordered broadcast, you will need to start with Scenario B. However, have the broadcast that both receivers have in their respective filters be one of your own, using a private action string as #MisterSquonk suggested. In addition, have another BroadcastReceiver registered in the manifest, whose is for the real broadcast you're listening for. That receiver would simply call sendOrderedBroadcast() to send out the ordered broadcast that the other receivers are listening on.
Scenario D: Activity Regardless of Foreground
If some activity of yours needs to know about the broadcast, and it does not matter whether or not it is in the foreground, you need to rethink what you mean by that. Usually, this really means that the broadcast affects your data model in some way, in which case your concern should not be to let the activities know, but rather to update your data model, and use your already-existing "let the activities know about the data model change" logic handle the rest.
If, however, you are convinced that this is not part of your data model, you can implement Scenario B or Scenario C, plus stick some information in a static data member. Your activities can examine that static data member in onResume() to pick up the information about the broadcast when they return to the foreground.
If you're thinking "but, what if my process is terminated between the broadcast and the other activity coming to the foreground?", then your broadcast really is updating your data model, per the opening paragraph of this scenario.
If you're thinking "but, I want to update an activity that is doing work in the background", then the activity in question is broken. Activities should never be doing work in the background. That work should be delegated to some form of service, and there's a whole related set of scenarios for getting a broadcast to the service.
If you declare the BroadcastReceiver in the Manifest, it will always be active and be called even if the application is closed.

Why is registering IabBroadcastReceiver in Activity a bad idea?

In Google's in-app billing Trivial Drive sample, a BroadcastReceiver is registered to listen for messages about updated purchases, after the IabHelper setup has successfully completed.
The author however has included the following note:
Note: registering this listener in an Activity is a bad idea, but is done here
because this is a SAMPLE.
Why is this a bad idea for this listener?
This comment can be found in the OnIabSetupFinishedListener definition in the onCreate method of MainActivity in the source code for the Trivial Drive sample
My guess is that the BroadcastReceiver may get destroyed if it's in an Activity. BroadcastReceivers are usually declared in the manifest and are not manually instantiated by the developer, but by the OS. If it is registered in code, the only reference the Android OS has to the BroadcastReceiver is that particular instance which is tied to the lifecycle of the Activity it's contained in. If that Activity were to die/finish/stopped to save memory, then the BroadcastReceiver declared inside would most likely stop receiving updates.
As we know the broadcast receiver should not bounded with activity it should separate from activity lifecycle. Usually the broadcast receiver should define inside the androidmanifest file. Doing this allow activity can easy listen the update when it clearly visible to the user and avoid listen in case activity no long visible to the user by un register inside onStop/onDestroy.
The best way to implement it using Eventbus + Broadcast receiver class. Define the receiver into the android manifest. when the update come it will inform to the receiver class. We fire the event that will send to each activity that register event would receive this message. This way inside your application where you need the update you can easily subscribe and listen the event.
Thanks
Because if we register a BroadcastReceiver in Activity, then it's lifecycle is bind to the Activity's lifecycle. So when the Activity is destory, the Receiver will not worked. Therefore it can not receive any boardcasts while the Activity is not running.
May be you will lose the boardcast which of user's purchase.
In this sample, we always call mHelper.queryInventoryAsync(mGotInventoryListener);
in the Activity's OnCreate() function. So we don't worry about that as the author comment in the code.

Responding to broadcast message from activity

I have an intent service that broadcasts a message based on user action and my activity is registered to receive the message.
Now, after the activity receives the message, I want my activity to respond to it depending on the message passed.
I have the below questions:
1. Will the receiver be still called even if my activity is killed? I don't want this to happen but would like to know if this is possible
2. Should I check for the current state of the activity (like which life-cycle method is currently being executed) before updating the activity UI in response to the message? Are there any best practices for handling the same?
Any helpful insight is appreciated. Thanks in advance
The Receiver should be a member of the Activity.
Register # onResume(), unRegister # onPause(), or onStart()&onStop()
Now to answer your questions:
No, if u unregister it at the correct place in the lifecycle there is no reason
that the receiver will be called.
No, because if its called then u know that the activity is visible to the user. But u need to check the UI elements because their state could change.

Avoid registering duplicate broadcast receivers in Android

I am trying to create my first Android app. I would like a main-thread Activity (in my case: an ActionBarActivity) to receive notification of an event from a background Activity (in my case: an IntentService). I've read that using broadcasts should be the best way to do this.
To register a Broadcast Receiver for listening to broadcasts sent from the background activity, I am using the following code inside the main-thread activity:
// Register broadcast receiver
LocalBroadcastManager bManager = LocalBroadcastManager.getInstance(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.me.myBroadcast");
bManager.registerReceiver(bReceiver, intentFilter);
I tried putting this in the onCreate() method of my main-thread activity, but I quickly discovered that every time I restart the activity (e.g. closing the app and re-opening it), it seems to create "duplicate" broadcast receivers, which then trigger the Broadcast Receiver's onReceive() method multiple times whenever a single broadcast is sent. This is causing problems.
So I created a SharedPreferences file to save a boolean which remembers whether or not I have already created a Broadcast Receiver, so as to avoid creating duplicates. This works exactly as hoped, until I restart the device of course, after which the Broadcast Receiver is destroyed, and the app doesn't create a new one because the SharedPreferences boolean says it already has one.
I'm guessing I could patch this issue by setting up a new broadcast receiver to listen for a device reboot, which resets the SharedPreferences boolean, but I have this nagging feeling that I am overcomplicating things massively. What am I missing? Thanks for any help offered!!
To answer your question, you can ignore sharedprefs and register the broadcast receiver in onResume and unregister the receiver in onPause. This method is well described in Reporting Work Status(1) android doc. Note that, this way, you will get status updates only if Activity is in foreground. Use appropriate life cycle methods depending on your needs.
To report status back to foreground activity from service, my preference would have been ResultReceiver(2) class which feels natural compared to a broadcast. Also, if you need to report multiple status messages back, it will be clearer with statusCode param in onReceiveResult method of ResultReceiver class.

Android BroadcastReceiver Lifecycle: documentation wrong for dynamically registered receiver?

I define a BatteryInfo extends BroadcastReceiver class. I call its constructor once in my Activity onCreate(). I register it with Activity.registerReceiver in my onCreate().
I am trying to figure out whether I need to unregister it and/or set its reference to null in order to allow my Activity to die without leaking memory or clogging up intent senders in the system, or whether the system gracefully tosses everything associated with this on its own. Towards that end I am pondering the BroadcastReceiver Lifecycle where I read:
A BroadcastReceiver object is only valid for the duration of the call to onReceive(Context, Intent). Once your code returns from this function, the system considers the object to be finished and no longer active."
what does this mean? Obviously the object I have created with new BatteryInfo() and registered with registerReceiver() persists through the entire time my activity persists. I log results from it and see them that entire time. Obviously it has not become invalid after the first time its onReceive() was called.
I am wondering if this section of documentation perhaps applies only to BroadcastReceivers which are registered in the AndroidManifest? And that it is simply incorrect or irrelevant to BroadcastReceivers that are dynamically created and registered?
And of course, I am wondering what is proper clean up and derferencing for my dynamic receivers.
All you need to do for BroadcastReceivers in code is register and unregister them. That statement is to inform you that you can't do any work outside of the onReceive, for example in another thread, and return a value back to the BroadcastReceiver. To do that you would get the BroadcastReceiver to start a Service.

Categories

Resources