广播(Broadcast)是 Android 系统中跨组件、跨应用通信的核心机制,允许应用监听系统或自定义事件并响应。本文从广播类型 、使用方式 、版本兼容 、注意事项 及典型场景五个维度全面解析。
一、广播类型与使用场景
广播类型 | 特点 | 适用场景 |
---|---|---|
标准广播 | 完全异步,所有接收器同时接收,无法中断。 | 发送无需有序处理的事件(如自定义全局通知)。 |
有序广播 | 同步执行,接收器按优先级顺序处理,可中断传播。 | 需要拦截或修改广播结果的场景(如短信拦截)。 |
本地广播 | 仅应用内传播,通过 LocalBroadcastManager 实现,安全性高。 |
应用内部组件通信(如 Activity 与 Service 通信)。 |
系统广播 | 由系统触发,如网络状态变化、电量不足、时区变更等。 | 监听系统事件并响应(如网络恢复后自动同步数据)。 |
粘性广播 | 发送后仍保留在系统中,新注册的接收器仍能接收(Android 5.0+ 已废弃)。 | 旧版本兼容场景(已不推荐使用)。 |
二、广播的注册与发送方式
1、静态注册(Manifest 声明)
-
特点 :在
AndroidManifest.xml
中声明,应用未启动也能接收广播(如监听开机完成)。 -
代码示例:
xml<receiver android:name=".BootCompleteReceiver" android:exported="true"> <!-- 是否允许跨应用接收 --> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
-
注意事项:
- Android 8.0+ 限制静态注册的隐式广播(非应用专属广播),需使用显式 Intent 或动态注册。
2、动态注册(代码注册)
-
特点:通过代码注册,灵活控制生命周期,需手动注销避免内存泄漏。
-
代码示例:
kotlin// 注册广播 val filter = IntentFilter().apply { addAction("com.example.MY_CUSTOM_ACTION") addAction(ConnectivityManager.CONNECTIVITY_ACTION) // 网络变化 } val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { when (intent?.action) { "com.example.MY_CUSTOM_ACTION" -> handleCustomAction() ConnectivityManager.CONNECTIVITY_ACTION -> handleNetworkChange() } } } context.registerReceiver(receiver, filter) // 注销广播(通常在 onDestroy 中调用) override fun onDestroy() { super.onDestroy() context.unregisterReceiver(receiver) }
3、发送广播
-
标准广播:
kotlinval intent = Intent("com.example.MY_CUSTOM_ACTION").apply { putExtra("data", "Hello, Broadcast!") } context.sendBroadcast(intent)
-
有序广播:
kotlincontext.sendOrderedBroadcast(intent, null) // 第二个参数为权限
三、版本兼容性问题
版本 | 关键变更 | 适配方案 |
---|---|---|
Android 7.0+ | 禁止后台应用通过静态注册监听 CONNECTIVITY_ACTION 等隐式广播。 |
改用动态注册或 JobScheduler 监听网络状态。 |
Android 8.0+ | 限制静态注册的隐式广播(需显式声明 package 或使用动态注册)。 |
静态注册时添加 android:exported="false" 或使用 Intent.setPackage() 指定包名。 |
Android 9.0+ | 移除 WIFI_SCAN_AVAILABLE 、DEVICE_POWER_CONNECTED 等敏感广播的默认监听权限。 |
动态申请 ACCESS_FINE_LOCATION 等权限。 |
Android 10+ | 限制后台应用启动 Activity,需在广播接收器中添加 FLAG_ACTIVITY_NEW_TASK 。 |
启动 Activity 时设置 Flag: intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
四、注意事项与最佳实践
1、安全性优化
- 限制接收范围 :使用
android:permission
声明权限,避免恶意广播攻击。
xml
<receiver android:name=".MyReceiver"
android:permission="com.example.CUSTOM_PERMISSION">
<intent-filter> ... </intent-filter>
</receiver>
-
本地广播 :优先使用
LocalBroadcastManager
(AndroidX 已废弃) 避免跨应用风险。- 推荐替代方案 :
使用LiveData
或事件总线(如EventBus
、RxBus
)。
- 推荐替代方案 :
kotlin
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
2、性能优化
-
避免主线程阻塞 :在
onReceive()
中禁止耗时操作,超过 10 秒会导致 ANR。 -
异步处理 :使用
goAsync()
(API 11+)或启动 Service 执行后台任务。
kotlin
override fun onReceive(context: Context, intent: Intent) {
val pendingResult = goAsync()
thread {
// 执行耗时操作
pendingResult.finish()
}
}
3、内存泄漏预防
- 及时注销动态广播 :在
Activity
/Fragment
的onDestroy()
中调用unregisterReceiver()
。
4、隐式广播限制规避
- 显式指定包名:发送广播时指定目标应用包名。
kotlin
intent.setPackage("com.example.targetapp")
context.sendBroadcast(intent)
五、典型使用场景
1、应用内组件通信
- 场景:Activity 通知 Service 更新数据。
- 方案 :使用
LocalBroadcastManager
发送本地广播。
2、监听系统事件
-
场景:检测网络状态变化。
-
代码示例:
kotlin
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
context.registerReceiver(networkReceiver, filter)
3、跨应用通信
- 场景:应用 A 触发应用 B 的特定功能。
- 方案:发送带权限的显式广播,并在接收方声明相同权限。
六、常见问题与解决
1、接收不到广播
- 检查 Intent 的 Action 是否一致。
- 确认注册方式(静态/动态)是否匹配。
- 高版本系统需适配隐式广播限制。
2、动态注册的广播在屏幕旋转后失效
- 在
onResume()
中注册,onPause()
中注销(根据业务需求调整生命周期)。
3、粘性广播无法使用
- 替换为
LocalBroadcastManager
或事件总线库。
七、总结
场景 | 推荐方案 | 关键注意事项 |
---|---|---|
应用内通信 | LocalBroadcastManager | 避免跨应用暴露广播 Action |
监听系统事件 | 动态注册 + 权限检查 | Android 7.0+ 需动态注册部分系统广播 |
跨应用触发功能 | 显式广播 + 自定义权限 | 接收方需声明相同权限并验证发送方身份 |
后台任务触发 | WorkManager 替代广播 | 避免依赖广播执行后台耗时操作 |
通过合理选择广播类型、适配版本限制并遵循安全规范,可高效利用广播机制实现灵活通信,同时保障应用性能与安全性。