【问题标题】:Enable and disable a Broadcast Receiver启用和禁用广播接收器
【发布时间】:2011-04-11 16:30:31
【问题描述】:

我尝试使用此 PackageManager 方法启用和禁用广播接收器:

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

广播接收器已在清单中注册。接收器工作正常,但是当我尝试禁用它时,它仍然接收到广播消息。 当我通过“android:enabled="false"”禁用清单中的接收器时,接收器没有收到任何东西,但我无法启用它。

我从服务内部调用该方法。

    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 清单:

    <receiver android:name=".broadcast_receivers.OnNetworkChangedReceiver"
                android:enabled="true">
            <intent-filter>
                    <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
            </intent-filter>
    </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");
    }
}

我昨天也从 Activity 内部调用了该方法。我认为它有效,但今天没有任何效果了。 难道是我昨天误解为禁用接收器的意图(android.net.conn.CONNECTIVITY_CHANGE)有时会出现很大延迟?

PackageManager 的方法是正确的方向还是这个想法存在基本错误?

非常感谢, 斯文

【问题讨论】:

  • 顺便说一下@Sven,你最初的错误是一个很常见的错误。您需要的 ComponentName ("com.app", "com.app.broadcast_receivers.OnNetworkChangedReceiver");我意识到这个解决方案看起来很奇怪,因为包名似乎被列出了两次。而且由于“新 Android 向导...”在您第一次创建项目时可能只要求您提供一个包名称,因此很容易认为只有一个,但实际上它会获取您提供的字符串并分配到两个不同的包名,应用程序包名和活动包名。
  • 使用0而不是PackageManager.DONT_KILL_APP也可以帮助您摆脱活动,如果我正确阅读文档:developer.android.com/reference/android/content/pm/…SetComponentEnabledSetting部分。

标签: android broadcastreceiver


【解决方案1】:

嗯,你基本上拥有的似乎还可以。我在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);

当我没有任何需要安排的活动警报时,我使用它来禁用BOOT_COMPLETED 接收器。

我的猜测是您的ComponentName 设置不正确(例如,您的前导.)。试试我正在使用的构造函数,它以 ContextClass 作为参数。

【讨论】:

  • 非常感谢您的快速答复。我使用了你使用的构造函数,现在它可以工作了。
  • 假设我有一个引导接收器 - 在它的 onReceive 返回之前禁用它是否值得?它会在下次重启时运行吗?
  • @Mr_and_Mrs_D:如果设备重启时禁用,则不会调用。
  • 谢谢,我发现 :( 我以为更改不会持续存在 - 他们怎么会这样做?setComponentEnabledSetting 是否写在清单中?
  • @Mr_and_Mrs_D:“它不会减少一些开销吗?” -- 您的调用很可能会导致更多开销,因为它涉及进程间通信。 “由于接收器将与注册时广播的所有隐式意图进行匹配”——因为大多数在 Android 上工作的谷歌人都是有才华的开发人员,我想他们使用像 HashMap 这样的高级数据结构来提高这些查找的效率。此外,由于您无法确定您的更改是否真正提高了性能,因此您是在浪费时间。
【解决方案2】:

我认为使用 PackageManager 是在考虑你的情况。您有一个 BroadcastReceiver 有时需要忽略它正在侦听的广播。我可以想到两种简单的方法来解决这个问题:

1) 设置一个标志,您的接收器可以检查它以忽略或接受广播,并且完全不用担心启用/禁用它。

2) 以编程方式创建 BroadcastReceiver(甚至可以只是一个内部类),并在应用程序的给定部分根据需要注册和取消注册它。

总的来说,我发现用代码而不是 XML 定义我的 BroadcastReceivers 提供了更大的灵活性,并且通常对我来说更容易管理。

【讨论】:

  • 有些类型的广播(例如BOOT_COMPLETED)无法通过registerReceiver()进行有效注册。此外,过度依赖registerReceiver() 会导致您获得永久的服务——只是为了维护接收器而提供的服务——这很糟糕。禁用该组件是提高效率的好主意,特别是对于流行的系统广播,例如BOOT_COMPLETED
  • 非常好的点。程序化广播接收器确实需要负责任的注册/注销以避免永久服务。与往常一样,这取决于具体情况。
  • @CommonsWare 有没有办法只在 BOOT_COMPLETED 事件后启用广播接收器?我想在设备重新启动后立即启用接收器,从我的 SQLite 数据库中重新设置触发到期日期通知的警报,然后禁用广播接收器。如果使用 PendingIntents 设置警报,我可以禁用接收器吗?或者我是否需要始终保持启用状态(使第一个问题没有实际意义)?
  • @AJW:“如果使用 PendingIntents 设置警报,我可以禁用接收器吗?” - 如果那些 PendingIntents 将用于向接收器广播,则必须启用接收器才能接收这些广播.该接收器不需要导出,但需要启用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多