73

我需要一些帮助来了解我的广播接收器何时可以在刚刚在清单中注册而不是必须从正在运行的活动或服务中注册时工作。

因此,例如,如果我使用以下意图过滤器注册一个独立的接收器,它可以在没有服务/活动引用的情况下工作:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.blk_burn.standalonereceiver"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >

        <receiver android:name="TestReceiver">
            <intent-filter>
                <action android:name="android.media.AUDIO_BECOMING_NOISY"/>
            </intent-filter>
        </receiver>

    </application>

</manifest>

但是,如果我android.media.AUDIO_BECOMING_NOISYandroid.intent.action.HEADSET_PLUG接收器替换不会触发(Android 文档

根据我在本网站上找到的内容,您必须从已经运行的活动或服务中注册此接收器才能使其工作(发布)。

  • 谁能告诉我为什么在清单中调整您的意图过滤器时这不起作用,以及为什么您需要在后台运行一个引用/注册接收器的服务?

  • 是否有解决方法,以便我可以使用意图过滤器在我的应用程序清单中注册我的接收器android.intent.action.HEADSET_PLUG

  • 如何识别android 文档中的哪些广播操作需要服务或活动注册它们,而不是在清单中使用正确的过滤器?

4

2 回答 2

100

如果您的接收器已在清单中注册,并且您的应用程序未运行,则会创建一个新进程来处理广播。如果您在代码中注册它,它与您注册它的活动/服务的生命周期相关联。对于某些广播,如果它不存在,则创建一个新的应用程序进程实际上没有意义,或者有一些安全性、性能等方面的影响,因此您只能在代码中注册接收器。

至于HEADSET_PLUG广播,似乎你的想法是你已经运行的应用程序可以让它对 UI、音量等进行特定于应用程序的调整。如果你的应用程序没有运行,你不应该真正关心耳机被拔掉。

AFAIK,没有为所有广播汇总此信息的单一位置,但每个 Intent 都应在 JavaDoc 中包含有关如何注册和使用它的注释,但显然缺少某些地方。如果您对Intent.FLAG_RECEIVER_REGISTERED_ONLY的 Android 源代码树进行 grep,您应该能够编译一个列表。

于 2012-06-04T03:42:24.423 回答
30

像往常一样,可以在清单文件 AndroidManifest.xml 中配置广播接收器。以这种方式配置的 BroadcastReceiver 称为静态注册。

您可以使用以下元素在清单文件中注册您的接收器:

<receiver
   android:name=".ConnectivityChangeReceiver">
   <intent-filter>
      <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
   </intent-filter>
</receiver>

嵌套元素用于指定接收者应响应的事件。

动态广播接收器

作为替代方案,您可以在代码中动态注册 BroadcastReceiver 实现。您只需要在 Context 对象上调用 registerReceiver() 方法。

registerReceiver() 方法有两个参数:

registerReceiver() 方法的参数

  • receiver : 你要注册的 BroadcastReceiver
  • filter : IntentFilter 对象,指定您的接收者应该监听哪个事件。

当您以这种方式注册接收器时,只要组件存在,它就会一直存在,并且 Android 会向该接收器发送事件,直到创建组件本身被销毁。

正确处理生命周期是您的任务。因此,当您动态添加接收器时,请注意在 Activity 的 onPause() 方法中取消注册相同的接收器!

我建议在 Activity 的 onResume() 方法中注册接收器,并在 onPause() 方法中取消注册:

@Override
protected void onPause() {
   unregisterReceiver(mReceiver);
   super.onPause();
}

@Override
protected void onResume() {
   this.mReceiver = new ConnectivityChangeReceiver();
   registerReceiver(
         this.mReceiver, 
         new IntentFilter(
               ConnectivityManager.CONNECTIVITY_ACTION));
   super.onResume();
}

何时使用哪种方法注册

使用哪种方法注册 BroadcastReceiver 取决于您的应用程序对系统事件的处理方式。我认为您的应用想要了解系统范围的事件基本上有两个原因:

  • 您的应用围绕这些事件提供某种服务
  • 你的应用想要对状态变化做出优雅的反应

第一类的示例是需要在设备启动后立即运行的应用程序,或者在安装应用程序时必须开始某种工作的应用程序。Battery Widget Pro 或 App2SD 是这类应用程序的好例子。对于这种类型,您必须在 Manifest 文件中注册 BroadcastReceiver。

第二类的示例是表明您的应用程序可能依赖的环境发生变化的事件。假设您的应用程序依赖于已建立的蓝牙连接。你必须对状态变化做出反应——但只有当你的应用程序处于活动状态时。在这种情况下,不需要静态注册的广播接收器。动态注册的会更合理。

还有一些事件甚至不允许您静态注册。一个例子是每分钟广播一次的 Intent.ACTION_TIME_TICK 事件。这是一个明智的决定,因为静态接收器会不必要地耗尽电池电量。

于 2016-11-28T15:43:43.463 回答