BroadcastReceiver组件本质上是一个全局监听器,用于监听系统全局的广播消息。它可以非常方便地实现系统中不同组件之间的通信。
各种OnXxxListener是程序级别的监听器,这些监听器运行在指定程序所在进程中,当程序退出时,OnXxxListener监听器也就随之关闭了。但BroadcastReceiver属于系统级的监听器,它拥有自己的进程,只要存在与之匹配的Intent被广播出来,BroadcastReceiver就会被激发。
如果确实需要根据Broadcast来完成一项比较耗时的操作,则可以考虑通过Intent启动一个Service来完成该操作。不应考虑使用新线程去完成耗时的操作,因为BroadcastReceiver本身的生命周期很短,可能出现的情况是子线程可能还没有结束,BroadcastReceiver就已经退出了。如果BroadcastReceiver所在的进程结束了,虽然该进程内设还有用户启动的新线程,但由于该进程内不包含任何活动组件,因此系统可能在内存紧张时优先结束该进程。这样就可能导致BroadcastReceiver启动的子线程不能执行完成。
Broadcast被分为如下两种:
- Normal Broadcast(普通广播):Normal Broadcast是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高。但缺点是接收者不能将处理结果传递给下一个接收者,并且无法终止Broadcast Intent的传播。
- Ordered Broadcast(有序广播):Ordered Broadcast的接收者将按预先声明的优先级依次接收Broadcast。Ordered Broadcast接收者可以终止Bropadcast Intent的传播。另外,Ordered Broadcast的接收者可以将数据传递给下一个接收者,比如A得到Broadcast后,可以往它的结果对象中存入数据,当Broadcast传给B时,B可以从A的结果对象中得到A存入的数据。
Context提供的如下两个方法用于发送广播。
- sendBroadcast():发送Normal Broadcast。
- sendOrderedBroadcast():发送Ordered Broadcast。
对于Ordered Broadcast而言,系统会根据接收者声明的优先级别按顺序逐个执行接收者,优先接收到Broadcast的接收者可以终止Broadcast,调用BroadcastReceiver的abortBroadcast()方法即可终止Broadcast。如果Broadcast被前面的接收者终止,后面的广播接收者就再也无法获取到Broadcast了。对于Ordered Broadcast而言,优先接收到到Broadcast的接收者可以通过setResultExtras(Bundle)方法将处理结果存入Broadcast中,然后传给下一个接收者,下一个接收者
通过代码Bundle bundle=getResultExtras(true)可以获取上一个接收者存入的数据。
系统收到短信后,会发出Ordered Broadcast。如果想阻止用户收到短信,可以通过设置优先级,让自定义的BroadcastReceiver先获取到Broadcast,然后终止Broadcast。
BroadcastReceiver是一个全局监听器,因此BroadcastReceiver也就提供了让不同组件之间进行通信的新思路。比如程序有一个Activity、一个Service,而且该Service是通过startService()方法启动起来的,在正常情况下,这个Activity与通过startService()方法启动的Service之间无法通信,但借助于BroadcastReceiver的帮助,程序就可以以实现两者之间的通信了。
接收系统广播消息
除接收用户发送的广播之外,BroadcastReceiver还有一个重要的用途:接收系统广播。如果应用需要在系统特定时刻执行某些操作,就可以通过监听系统广播来实现。Android的大量系统事件
都会对外发送标准广播。例如下面是Android常见的广播Action常量。
- ACTION TIME_CHANGED:系统时间被改变。
- ACTION DATE CHANGED:系统日期被改变。
- ACTION_TIMEZONE_CHANGED:系统时区被改变。
- ACTION BOOT COMPLETED:系统启动完成。
开机自动运行的Activity
如果需要使用开机自动运行的Service,例如监听用户来电、监听用户短信、拦截黑名单电话......为了让Service随系统启动自动运行,可以让BroadcastReceiver监听Action为ACTION BOOT COMPLETED常量的Intent,然后在BroadcastReceiver中启动特定Service即可。但从Android8开始,开机启动的BroadcastReceiver不允许在后台启动Service,这也是出于保护用户安全的考虑,因为这种开机启动、在后台运行的Service一方面会带来安全隐患;另一方面会影响Android系统的性能。
为了让LaunchReceiver监听系统开机发出的广播,因此需要在AndroidManifest.xml文件中采
用如下代码配置该BroadcastReceiver。
<!--定义一个BroadcastReceiver,监听系统开机广播
<receiver android:name=".LaunchReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
除此之外,为了让程序能访问系统开机事件,还需要为应用程序增加如下权限。
<!--授予应用程序访问系统开机事件的权限-->
<uses-permission android:name="android.permission.RECEIVE BOOT COMPLETED"/>
该应用只要运行过一次,那么以后每次重启手机,该应用都会自动运行。
android:exported
android:exported 对于有 intent-filter 情况 下默认值为 true
BroadcastReceiver 动态声明为 RECEIVER_NOT_EXPORTED 后无法接收任何 Intent 的问题
自 Android 14 (API 级别 34) 起,使用 context.registerReceiver(receiver, filter, flags) 动态注册广播接收器时,必须显式地声明 RECEIVER_NOT_EXPORTED 或 RECEIVER_EXPORTED 。如果声明为 RECEIVER_EXPORTED ,任何第三方应用都能向你的应用发送不受保护的广播,有潜在的安全隐患。
在安卓14中发送广播时必须为 Intent 指定 package ,否则BroadcastReceiver收不到任何Intent。
context.sendBroadcast(Intent(PUSHSETTING).apply {
`package` = context.packageName
})
android:process
- 默认行为:若不设置该属性,所有组件默认运行在以包名命名的主进程中 。
- 私有进程(推荐):以冒号
:开头(如:remote)。- 冒号后的字符串可自定义,但最终进程名会自动拼接为
包名:自定义后缀(例如包名com.example+:remote=com.example:remote)。 - 该进程仅当前应用可见,其他应用无法访问,安全性高。
- 冒号后的字符串可自定义,但最终进程名会自动拼接为
- 全局进程:以小写字母开头且包含点号 (如
com.example.shared)。- 名称必须符合 Java 包名规范(小写字母、数字、下划线或句号),不能以大写字母或特殊符号开头。
- 只有当多个应用拥有相同的 Linux UID 且使用相同证书签名时,才能共享此进程,否则系统会拒绝启动或报错。
- 非任意性:不可以随意指定一个已存在的系统进程或其他应用的进程名,除非满足 UID 和签名一致的条件。
- 副作用:设置独立进程会导致
Application实例在该进程中重新创建,静态变量失效,需通过 IPC(如 AIDL、Messenger)进行通信 。
LocalBroadcastManager
LocalBroadcastManager 是 Android 中用于在应用进程内部发送和接收广播的工具类,旨在替代全局广播以提升安全性和效率。需注意:该组件在旧版 Support 库中已标记为废弃(Deprecated),新项目应优先使用 AndroidX 版本或更现代的架构组件(如 LiveData、Flow、EventBus 等)。
核心特性
- 作用域小:广播仅在当前应用进程内传播,其他应用无法接收或发送,杜绝数据泄露和安全漏洞。
- 高效性:无需经过系统层(AMS),无进程间通信(IPC)开销,性能优于全局
sendBroadcast()。 - 生命周期管理:需手动注册与注销接收器,避免内存泄漏。
- 线程模型:
sendBroadcast()为异步调用,通过主线程 Handler 分发;sendBroadcastSync()为同步,不可在子线程调用,否则可能阻塞。 - 多进程问题:若应用包含多个进程,每个进程有独立的 LocalBroadcastManager 实例,跨进程通信无效。
- 替代方案建议:对于新开发推荐使用 Jetpack 组件(如
LiveData、StateFlow)或事件总线库,它们提供更强的生命周期感知和类型安全。
本文探讨了在Android应用安装后自动添加桌面图标及自启动的方法。由于直接通过BroadcastReceiver捕获Add消息不可行,文章提出了一种通过辅助应用实现的折中方案。

3066

被折叠的 条评论
为什么被折叠?



