Enable and disable a Broadcast Receiver

44,293

Solution 1

Well, what you basically have seems OK. I have the following code in one of my projects:

boolean enabled=prefs.getBoolean(key, false);
int flag=(enabled ?
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
ComponentName component=new ComponentName(EditPreferences.this, OnBootReceiver.class);

getPackageManager()
    .setComponentEnabledSetting(component, flag,
                                PackageManager.DONT_KILL_APP);

I use this to disable a BOOT_COMPLETED receiver when I don't have any active alarms that need to be scheduled.

My guess is that your ComponentName is not set up properly (e.g., your leading .). Try the constructor that I am using, that takes a Context and a Class as parameters.

Solution 2

I think using the PackageManager is over-thinking your situation. You have a BroadcastReceiver that needs to sometimes ignore the broadcasts it's listening for. I can think of two easy ways to go about this:

1) Set a flag that your receiver can check to ignore or accept broadcasts, and don't worry about enabling/disabling it at all.

2) Create the BroadcastReceiver programmatically (can just be an inner class, even), and register and unregister it as you need at given parts of your application.

In general I've found that defining my BroadcastReceivers in code instead of XML has provided a lot more flexibility and is generally easier for me to manage.

Share:
44,293

Related videos on Youtube

Sven
Author by

Sven

Updated on May 28, 2020

Comments

  • Sven
    Sven almost 4 years

    I try to enable and disable a broadcast receiver by using this PackageManager method:

    setComponentEnabledSetting(componentName,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);
    

    The broadcast receiver is registered in the manifest. The receiver works fine but when i try to disable it, it still receives the broadcast messages. When i disable the receiver in the manifest by "android:enabled="false"", the receiver does not receive anything but I can not enable it.

    I call the method from inside a service.

        PackageManager pm  = getApplicationContext().getPackageManager();
        ComponentName componentName = new ComponentName("com.app",
                 ".broadcast_receivers.OnNetworkChangedReceiver");
        pm.setComponentEnabledSetting(componentName,
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
    

    Android manifest:

        <receiver android:name=".broadcast_receivers.OnNetworkChangedReceiver"
                    android:enabled="true">
                <intent-filter>
                        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
                </intent-filter>
        </receiver>
    

    The Receiver

    public class OnNetworkChangedReceiver extends BroadcastReceiver {
    private static final String TAG = "OnNetworkChangedReceiver";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "in OnNetworkChanged");
        }
    }
    

    I also called the method from inside an Activity yesterday. I thought it worked but today nothing works anymore. Could it be that there is sometimes a big delay in the intent (android.net.conn.CONNECTIVITY_CHANGE) that I misinterpreted yesterday as disabling the receiver?

    Is the approach with the PackageManager the right direction or is there a basic error in the idea?

    Thanks a lot, Sven

  • CommonsWare
    CommonsWare about 13 years
    There are some types of broadcasts (e.g., BOOT_COMPLETED) that cannot be effectively registered via registerReceiver(). Also, over-reliance on registerReceiver() leads you to everlasting services -- services just there to maintain a receiver -- which is bad. Disabling the component is a good idea for efficiency, particularly with popular system broadcasts, like BOOT_COMPLETED.
  • LeffelMania
    LeffelMania about 13 years
    Very good points. Programmatic BroadcastReceivers do necessitate responsible registering/unregistering to avoid everlasting services. As always it depends on the situation.
  • Sven
    Sven about 13 years
    Thanks a lot for the fast answer. I used the constructor you used and now it works.
  • Mr_and_Mrs_D
    Mr_and_Mrs_D about 11 years
    Say I have a Boot Receiver - would it be any worth disabling it just before its onReceive returns ? Would it then run on next reboot ?
  • CommonsWare
    CommonsWare about 11 years
    @Mr_and_Mrs_D: If it is disabled when the device reboots, it will not be invoked.
  • Mr_and_Mrs_D
    Mr_and_Mrs_D about 11 years
    Thank you I found out :( I thought the changes would not persist - how come they do ? Does setComponentEnabledSetting write in the manifest ?
  • CommonsWare
    CommonsWare about 11 years
    @Mr_and_Mrs_D: "I thought the changes would not persist" -- then there would have been no point in your trying to disable the receiver, as the boot would already have happened. "how come they do ?" -- because that is the complete and entire point behind setComponentEnabledSetting().
  • Mr_and_Mrs_D
    Mr_and_Mrs_D about 11 years
    "then there would have been no point in your trying to disable the receiver, as the boot would already have happened" - would it not remove some overhead ? - Since the receiver will be matched against all implicit intents broadcasted while it is registered [it won't actually respond (its onReceive() wont run) as I test for the action (to avoid malicious explicit intents) and I have the BOOT_COMPLETED filter active - so implicit intents won't match, apart from the BOOT one]
  • CommonsWare
    CommonsWare about 11 years
    @Mr_and_Mrs_D: "would it not remove some overhead ?" -- most likely you are causing more overhead by your call, as it involves inter-process communication. "Since the receiver will be matched against all implicit intents broadcasted while it is registered" -- since most of the Googlers working on Android are talented developers, I would imagine that they use advanced data structures like HashMap to make these lookups efficient. Moreover, since you cannot determine whether your change actually improves performance, you are wasting your time.
  • Andy Dennie
    Andy Dennie over 9 years
    Major caveat: be aware that enabling or disabling a component with DONT_KILL_APP on API 14 or 15 will wipe out any notifications your app has created. See code.google.com/p/android/issues/detail?id=21635
  • Andy Dennie
    Andy Dennie over 9 years
    clarification: my previous comment applies to "ongoing" notifications.
  • GPack
    GPack over 7 years
    @CommonsWare Please, i dont understand clearly what the flag DONT_KILL_APP is useful for. Is not the Receiver's onReceive() already guaranteed to be executed completely (with limit of 10 secs)?
  • CommonsWare
    CommonsWare over 7 years
    @GPack: It is a flag for setComponentEnabledSetting() that controls whether the process should be terminated when we are toggling whether a component is enabled or not. It has nothing directly to do with any onReceive() method.
  • AJW
    AJW almost 6 years
    @CommonsWare Is there a way to only enable the BroadCastReceiver after a BOOT_COMPLETED event? I would like to enable the Receiver immediately after the device re-boots, re-set alarms from my SQLite database that fire due date Notifications and then disable the BroadCastReceiver. Can I disable the Receiver if the alarms are set up with PendingIntents or do I need to always leave enabled (rendering the first question moot)?
  • CommonsWare
    CommonsWare almost 6 years
    @AJW: "Can I disable the Receiver if the alarms are set up with PendingIntents" -- if those PendingIntents will be for broadcasts to the receiver, the receiver must be enabled to receive those broadcasts. That receiver does not need to be exported, but it does need to be enabled.

Related