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.
Related
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.
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.
Few days ago I read that there is a better mechanism for sending broadcasts within single application - the LocalBroadcastManager.
It works well (just like standard broadcasts..). However, yesterday I've found out that it cannot send broadcasts to receivers, which are defined in the manifest (when I temporarily switched it to use the standard Activity's sendBroadcast method, it worked).
The reason why I want this (and correct me if there is a more preferred way to do it) is:
Lets's say I want to download a file. I will use a service, because that's how Android wants us to do. OK, now I want to display (and periodically update) its progress in my activity. So service will be sending broadcasts to my activity and the activity has to register to receive them. The preferred way to handle broadcasts is to register in onResume() and unregister in onPause(). Now let's imagine that the user is bored with the slowly moving progressbar, so he presses Home and goes to do something else. Later he comes back and wants to see the current status of the download, but how can I tell him, when I unregistered from broadcasts that second he left my application?
That's why I use a receiver defined in the manifest, to be always ready to receive the broadcast and store it permanently (shared preferences, database...), so the activity can reconstruct the latest broadcast when it becomes visible.
However now I'm not sure, whether this routine is not recommended, or why the LocalBroadcastManager is not allowing me to do it.
If you are using SharedPreferences a workaround would be to make your activity implement OnSharedPreferenceChangeListener. So the service writes the pref and the activity listens for the change and updates progress bar. onResume() you also check the preference and update the UI accordingly.
The nice thing with this is you don't really have a leak if you fail to unregister them - see
Android : Where should a OnSharedPreferenceChangeListener be defined/registered - I prefer to unregister to onDestroy() as I want to have my activity updated even if not in the foreground - and the listener will go away even if onDestroy is not called.
As for why it does not work with manifest registered receivers - could you post some code ? Do you actually register the receivers with LBM ?
I use certain sounds to notify the user of certain events. However, I do not want the app to notify the user with sounds if the activity is not on foreground.
How can I check if the app is running on background or not?
Expanding on mco's answer, your GCMIntentService needs to do something that will trigger work in a foreground activity of yours, if you have a foreground activity. Typically, you will do this by setting up your activities to respond to some sort of message in onResume() and removing that in onPause().
"Some sort of message" could be:
An Intent sent via LocalBroadcastManager
An Intent sent via the classic sendBroadcast()
A message via a message bus, like Otto
Etc.
In the Activity cycle, onResume is called when the app becomes visible (foreground) and onPause is called when it is not visible (background).
You can use these functions to do whatever you want to do when the app is background/foreground.
If you register and unregister broadcast receivers on the methods onPause and onResume on every activity,
is there a chance to miss some of the broadcasts when you switch between activities? There is some time between those two methods, and if in that point a broadcast is triggered, will the app skip it?
Thanks for the information,
Dan
there will be a brief moment where they will not be catches.
i would propose to delay the unregister for a sec by using postDelayed in the Handler class
but that way it might be captured on both at the same time .
i cant propose a solution unless you have a scenario .
for example in my application it is not essential to handle this case because every activity has its own use of the Broadcasts and thus i don't care about this case.