1. 什么是 BroadcastReceiver?
BroadcastReceiver(广播接收器)是 Android 四大组件之一,它就像是一个"订阅者":系统或应用会发出各种各样的"广播消息",而你可以编写一个 BroadcastReceiver 来监听并响应你感兴趣的消息,比如:
-
设备电量低了
-
网络连接状态发生了变化
-
用户拔掉了耳机
-
应用安装或卸载
-
闹钟时间到了
简单说,BroadcastReceiver 让你能监听系统全局事件或自定义事件,并做出响应。
2. BroadcastReceiver 的作用与应用场景
2.1 监听系统事件
无需实时运行,只在事件发生时被系统唤醒并执行一段代码,省电又高效。
2.2 应用内/跨应用通信
你可以在自己 App 内部发送广播让不同组件收到消息,也可以让其他 App 收到你发的广播(或监听其他 App 的广播),实现解耦。
2.3 开启其他组件
收到广播后,可以启动一个 Activity、Service 或发通知,但注意后台执行限制。
2.4 典型场景
-
电量变化:电量低于 20% 时提示用户或自动进入省电模式。
-
网络变化:Wi-Fi 断开时自动暂停下载。
-
耳机插拔:音乐 App 检测到耳机拔出时自动暂停播放。
-
应用安装/卸载:清理与该应用相关的缓存文件。
-
闹钟/定时任务 :结合
AlarmManager执行定时任务(但有更优方案)。 -
应用内通信:购物车更新,通知其他页面刷新。
3. 广播的类型
从传播方式看,广播分为两类:
| 类型 | 特点 | 典型使用 |
|---|---|---|
| 标准广播(Normal Broadcasts) | 完全异步,所有接收器几乎同时收到,无法被拦截,不可被修改。 | 系统通知:时区变更、屏幕开启等。 |
| 有序广播(Ordered Broadcasts) | 一次发送给一个接收器,按优先级顺序传递,前面的接收器可以修改结果甚至中止广播。 | 需要处理顺序的场景,如短信拦截。 |
从广播来源看,分为系统广播 和自定义广播 。系统广播由 Android 系统发送,如 ACTION_BOOT_COMPLETED(开机完成);自定义广播则是开发者自己发送的。
4. 如何接收广播:注册 BroadcastReceiver
想让 BroadcastReceiver 监听广播,必须进行注册 。注册方式有两种:静态注册 (清单文件)和动态注册(代码)。
4.1 静态注册(清单注册)
在 AndroidManifest.xml 中声明,即使应用未启动,也能接收广播(受版本限制,见 7.3 节)。系统广播中的开机广播、应用安装等必须使用静态注册才能收到。
步骤:
-
创建一个类,继承
BroadcastReceiver,实现onReceive()。 -
在
<application>节点下注册<receiver>,并添加<intent-filter>指定要监听的广播动作。
示例:监听开机完成广播
kotlin
// MyBootReceiver.kt
class MyBootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
// 开机完成,可以做初始化操作
}
}
}
在 AndroidManifest.xml 中:
xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application...>
<receiver
android:name=".MyBootReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
注意:从 Android 8.0 (API 26) 开始,大部分系统广播无法再通过静态注册接收(除了少数白名单广播,如开机,见 7.3)。
4.2 动态注册(代码注册)
在 Activity 或 Service 等组件中通过代码注册,通常与生命周期绑定,应用退出后自动失效(因为组件销毁)。
步骤:
-
实例化自定义的
BroadcastReceiver。 -
创建
IntentFilter,添加要监听的动作。 -
调用
registerReceiver(receiver, filter)进行注册。 -
别忘了在合适时机取消注册 (如
onPause/onStop中调用unregisterReceiver()),避免内存泄漏或异常。
示例:监听网络变化
kotlin
class MainActivity : AppCompatActivity() {
private val networkReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// 网络状态变化,更新 UI
}
}
override fun onStart() {
super.onStart()
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
registerReceiver(networkReceiver, filter)
}
override fun onStop() {
super.onStop()
unregisterReceiver(networkReceiver)
}
}
注意 :CONNECTIVITY_ACTION 在 Android 7.0 (API 24) 及更高版本同样受到后台限制,建议使用 ConnectivityManager.NetworkCallback 代替广播监听网络变化。这里只是为了演示动态注册的步骤。
4.3 两种注册方式对比
| 特性 | 静态注册 | 动态注册 |
|---|---|---|
| 何时接收 | 应用未启动时也能收到(限制广播) | 只在组件存在时才能接收 |
| 生命周期 | 独立于组件,有广播就调用 | 随注册组件(Activity等)生命周期 |
| 系统开销 | 相对重,常驻内存 | 轻量,随组件回收 |
| 适用场景 | 需要开机自启等必需场景 | 大部分应用内实时监听场景 |
| 取消注册 | 无需手动取消 | 必须手动取消(通常在 onStop/onDestroy) |
5. 发送广播
你可以发送系统定义的广播,但通常开发者发送的是自定义广播。
5.1 发送标准广播
kotlin
val intent = Intent("com.example.MY_CUSTOM_ACTION")
intent.putExtra("key", "value")
// 发送给所有匹配的接收器(包括其他App)
sendBroadcast(intent)
// 如果需要限制接收方,可以添加权限
// sendBroadcast(intent, "com.example.MY_PERMISSION")
5.2 发送有序广播
kotlin
val intent = Intent("com.example.MY_ORDERED_ACTION")
// 最后一个参数为最终接收器,当所有接收器处理完后如果没有被中止,会收到结果
sendOrderedBroadcast(intent, null, object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// 最终执行,可以获取到前面接收器设置的结果
val resultData = resultData
}
}, null, Activity.RESULT_OK, null, null)
在有序广播的接收器中,可以:
-
setResultData(data)修改数据 -
abortBroadcast()中止传递(需要权限,且仅对有序广播有效)
5.3 应用内发送(LocalBroadcastManager,已弃用)
为了安全和性能,过去常使用 LocalBroadcastManager 限制广播仅在进程内传递。但从 AndroidX 开始,此组件已被弃用 ,官方建议用 LiveData、Flow 或 EventBus 替代。如果你仍需要应用内广播,可以使用带有自定义权限的广播,或直接使用观察者模式。
6. BroadcastReceiver 的生命周期
BroadcastReceiver 的生命周期非常短暂,只在 onReceive() 方法执行期间有效。
-
onReceive(context, intent) :当广播被接收时调用。该方法在主线程 执行,必须在 10 秒内完成,否则会导致 ANR。
-
BroadcastReceiver对象在onReceive()返回后会变成无效状态(不再活跃),系统随时可能回收。
绝对不要在 onReceive() 中做耗时操作 (如网络请求、复杂计算、大文件读写)。如果必须做耗时操作,正确的做法是启动一个 Service(某些情况下受限制)或调度 WorkManager 任务。
7. 权限与安全
7.1 发送广播时添加权限
防止未授权的应用接收你的广播:
kotlin
sendBroadcast(intent, "com.example.MY_PERMISSION")
只有声明了 MY_PERMISSION 权限的接收器才能收到该广播。
7.2 接收广播时要求发送方持有权限
在注册接收器时,你可以在 registerReceiver() 中指定一个 broadcastPermission,只有持有该权限的发送方才能向你的接收器发送广播。同样,静态注册时可使用 android:permission 属性。
7.3 Android 版本注意事项(必读)
-
Android 8.0 (API 26) :除了少数隐式广播(如开机广播),静态注册的隐式广播接收器将不再工作 。大部分系统广播必须动态注册。发送隐式广播(即目标是 action 而非组件类名)也受到限制,建议使用显式广播(指定
ComponentName)。 -
Android 14 (API 34):进一步收紧,隐式广播发送者可能需要申报权限,且缓存广播更加严格。
-
为了兼容性 :对于需要一直运行的功能,考虑使用
WorkManager或JobScheduler代替广播接收器。
白名单广播 (可在清单中静态注册而无需应用运行)包括:ACTION_BOOT_COMPLETED、ACTION_LOCALE_CHANGED 等,具体参考官方文档。
8. 实战演练:一个电量变化监听小案例
假设我们要做一个在电量低于 15% 时提醒用户的功能。因为 ACTION_BATTERY_LOW 是粘性广播且不允许静态注册,我们用动态注册监听 ACTION_BATTERY_CHANGED(但该广播只能动态注册,且系统会频繁发送)。
代码清单(在 Activity 中):
kotlin
class BatteryActivity : AppCompatActivity() {
private lateinit var batteryReceiver: BroadcastReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_battery)
batteryReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
val batteryPct = level * 100 / scale.toFloat()
if (batteryPct < 15) {
// 低电量,发通知或显示对话框
showLowBatteryWarning()
}
}
}
}
override fun onStart() {
super.onStart()
val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
registerReceiver(batteryReceiver, filter)
}
override fun onStop() {
super.onStop()
unregisterReceiver(batteryReceiver)
}
private fun showLowBatteryWarning() {
// 这里可以发通知
}
}
9. 静态注册自定义广播的完整例子(仅应用内)
如果你想在应用内用静态注册接收自定义广播(例如通知其他组件),可以使用显式广播以保证安全且不受系统限制。
发送方:
kotlin
val intent = Intent(this, MyInternalReceiver::class.java)
intent.action = "com.example.INTERNAL_ACTION"
sendBroadcast(intent)
接收方(清单中注册,exported=false 确保安全):
xml
<receiver
android:name=".MyInternalReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.example.INTERNAL_ACTION" />
</intent-filter>
</receiver>
kotlin
class MyInternalReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// 响应内部事件
}
}
10. 常见问题与最佳实践
10.1 别忘了取消动态注册
动态注册必须在合适的生命周期方法中取消,通常 onPause 或 onStop 中执行 unregisterReceiver()。否则当你退出 Activity 后接收器仍然存在,系统会抛出 leaked 异常,严重时导致崩溃。
10.2 不要做耗时操作
onReceive 运行在主线程,应迅速返回。耗时任务应:
-
启动
Service(注意后台限制) -
使用
goAsync()(需要 API 11+,但较少使用) -
调度
WorkManager
10.3 尽量减少静态注册,多用动态 + 生命周期感知组件
Android 8.0+ 限制后,静态注册的用途已经很有限。除非你确实需要应用不在运行时接收广播,否则建议动态注册,并结合 LiveData 或 Lifecycle 组件自动管理注册/取消。
10.4 使用 LocalBroadcastManager 的替代品
LocalBroadcastManager 被弃用,建议使用以下替代:
-
LiveData / SharedFlow:组件间通信。
-
EventBus(GreenRobot):轻量级事件总线。
-
Kotlin Flow:应用内数据流。
-
如果必须使用广播,且仅限应用内,可以使用带权限的显式广播。
10.5 Android 13 (API 33) 引入的通知权限
如果你的广播接收器会弹出通知,需要确保已获得通知权限(POST_NOTIFICATIONS)。对于静态注册的接收器启动前台服务,也会受到新限制,详细查阅对应版本的行为变更。
11. 总结
-
BroadcastReceiver是 Android 中一个轻量级的消息订阅组件,用于接收系统或应用内广播消息。 -
注册方式分为静态注册 (清单)和动态注册(代码),目前大部分场景使用动态注册。
-
广播分为标准广播 和有序广播,后者可以按优先级处理和中止。
-
注意版本适配,尤其是 Android 8.0 以后对静态注册的隐式广播限制,以及 Android 14 的进一步收紧。
-
始终在合适的生命周期取消动态注册,避免泄漏;
onReceive()中不做耗时操作。 -
谨慎使用广播的应用内通信,可逐步用
LiveData/Flow替换,但广播仍有用武之地。
延伸阅读推荐: