清单与活动中的广播接收器注册

Posted

技术标签:

【中文标题】清单与活动中的广播接收器注册【英文标题】:Broadcast Receiver Register in Manifest vs. Activity 【发布时间】:2012-06-08 05:08:04 【问题描述】:

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

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

<?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_NOISY 替换为 android.intent.action.HEADSET_PLUG,则不会触发接收器 (Android Documentation)

根据我在此站点上的发现,您必须从已在运行的活动或服务中注册此接收器才能使其工作 (Post)。

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

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

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

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

intent.Flag.. 并在源代码中找到它是有意义的。谢谢 第一段..脱帽致敬 :) 你有没有官方文件支持你的说法(如果你的receiver在manifest中注册了并且你的app没有运行,会创建一个新的进程来处理广播。)? @BehzadBahmanyar 下面的链接是我能找到的最接近的东西。 developer.android.com/reference/android/content/…. @BehzadBahmanyar 也可以在这个问题中查看 CommonsWare 的 cmets:***.com/a/3652085/2818583【参考方案2】:

像往常一样,可以在清单文件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 事件。这是一个明智的决定,因为静态接收器会不必要地耗尽电池电量。

【讨论】:

说得很好,兄弟。 解释得很好。

以上是关于清单与活动中的广播接收器注册的主要内容,如果未能解决你的问题,请参考以下文章

android 学习随笔十八(广播与服务 )

从清单注册时未调用广播接收器

活动中的广播接收器

android 广播接收不到可能是哪里出了问题

android 注册广播有多少种方式

使用 Manifest 注册广播接收器