BroadcastReceivers are good when you want to be notified about system events. But sometimes you do need to know about an event only once or for a short period of time.
A dynamically registered receiver doesn't cut it because the Activity and it's dynamically registered broadcast receiver might long be dead when the event occurs. The only way to achieve this is by enabling and disabling broadcast receivers in your code.
Enabling or Disabling BroadcastReceivers
You enable or disable receivers by using methods of the PackageManager class. With this class you can enable and disable app components at runtime:
PackageManager pm = getPackageManager(); ComponentName compName = new ComponentName(getApplicationContext(), YourReceiver.class); pm.setComponentEnabledSetting( compName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
There are three states the PackageManager offers for this:
|COMPONENT_ENABLED_STATE_DEFAULT||Sets the state to the manifest file value|
|COMPONENT_ENABLED_STATE_DISABLED||Sets the state to disabled|
|COMPONENT_ENABLED_STATE_ENABLED||Sets the state to enabled|
By default the
PackageManager kills your app immediately, since a component state change could lead to unpredictable situations. The flag
DONT_KILL_APP prevents this from happening and is safe to use for BroadcastReceivers. Of course if you do not use the
DONT_KILL_APP-flag, you will spot your mistake even with the most cursory of testings 🙂
Disabling BroadcastReceivers by default
If you want to enable your receiver at runtime, you can set the state to disabled initially. You can do so in the manifest file:
<receiver android:name=".YourReceiver" android:enabled="false" > <!-- your intent filter --> </receiver>
When to use this
The basic reason why you should do this, is that you want to preserve valuable resources on your user's devices. You do not want to drain the battery by running code that is not relevant to your user. Most often you can achieve this by using a dynamically registered receiver. But this does not always work.
Three examples where you should explicitly use the PackageManager-solution presented above:
1. You might need to know about the next boot, but only the next one. In this case you cannot use a dynamically registered receiver. You have to use a statically registered one. But you do not want to run it on every boot completion. Which means that you have to disable the receiver after it's first run.
2. If one or more receivers depend on the state of a specific system service you can disable all of them for as long as the necessary service is not in the desired state. This could be true for network connectivity, while waiting for a GPS fix, for missing Bluetooth availabilty and such.
3. You intend to use notifications - but only if the app is not currently active. In this case your
BroadcastReceiver has to be enabled by default. But you would disable it in your Activities'
onResume() method and re-enable it in the
See also Reto Meier's blog post about location-based apps and have a thorough look at the accompanying source code. He covered these topics initially in his talk at Google's IO 2011. I highly recommend to watch the video of this talk. It's definitely a good watch!