有序广播与本地广播
本教程共 100 篇 · 第 36 篇 · 更新于 2026-07-28 · 约 7 分钟阅读
36. 有序广播与本地广播
本节目标:分清普通广播、有序广播、本地广播三种类型的区别,学会用有序广播传递数据、用本地广播做应用内通信、用权限保护广播安全。
上一节我们接触的是「普通广播」—用 sendBroadcast() 发送,所有接收器几乎同时收到,互不影响。这节来看另外两种特殊广播。
有序广播
还是用比喻:普通广播像群发消息,大家同时收到各看各的;有序广播像传纸条,A 看完传给 B,B 看完传给 C,中途谁都能改内容,甚至能把纸条截下来不传了。
有序广播用 sendOrderedBroadcast() 发送,接收器按优先级逐个执行。每个接收器可以:
- 读取上一个接收器传下来的结果
- 修改或追加数据传给下一个
- 调用
abortBroadcast()终止广播,后面的接收器就收不到了
发送有序广播
val intent = Intent("com.example.app.ORDERED_ACTION").apply {
putExtra("message", "原始消息")
setPackage("com.example.app") // 限定包名
}
// 第二个参数是权限,传 null 表示不限制
context.sendOrderedBroadcast(intent, null)
设置优先级
优先级在 IntentFilter 里设置,数值越大越先收到:
val filter = IntentFilter("com.example.app.ORDERED_ACTION").apply {
priority = 100 // 高优先级先收到
}
ContextCompat.registerReceiver(
context, highPriorityReceiver, filter,
ContextCompat.RECEIVER_NOT_EXPORTED
)
XML 里也能设置:
<intent-filter android:priority="100">
<action android:name="com.example.app.ORDERED_ACTION" />
</intent-filter>
Warning在 Android 16 中,跨进程的广播优先级已经不再保证顺序。
android:priority只在同一应用进程内有效。如果你的多个接收器在同一应用里,优先级还有用;跨应用就别指望顺序了。
在接收器间传递数据
class FirstReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val msg = intent.getStringExtra("message")
// 把结果传给下一个接收器
setResultData("$msg -> 第一站处理完毕")
}
}
class SecondReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// 拿到上一个接收器传来的结果
val previousResult = getResultData()
Log.d("SecondReceiver", "收到: $previousResult")
// 也可以终止广播,后面就收不到了
// abortBroadcast()
}
}
getResultData() / setResultData() 传递字符串,getResultExtras() / setResultExtras() 传递 Bundle,适合传复杂数据。
获取最终结果
如果只想知道最后一个接收器处理完的结果,可以用带 resultReceiver 参数的版本:
context.sendOrderedBroadcast(
intent,
null, // 权限
finalReceiver, // 所有接收器跑完后再回调这个
null, // Handler,null 表示主线程
0,
"初始数据",
null
)
本地广播
普通广播有个问题:用 sendBroadcast() 发出去,其他应用也能收到。如果只是应用内部传消息,用普通广播既不安全(可能被别的应用截获),又低效(要跨进程)。
本地广播(Local Broadcast)就是解决这个问题的。它只在应用内部传递,不跨进程,收发都更快更安全。
用法
本地广播需要 androidx.localbroadcastmanager 库。先加依赖:
dependencies {
implementation("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0")
}
发送本地广播:
val intent = Intent("com.example.app.LOCAL_ACTION").apply {
putExtra("data", "应用内部消息")
}
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
注册接收器也要通过 LocalBroadcastManager:
override fun onStart() {
super.onStart()
val filter = IntentFilter("com.example.app.LOCAL_ACTION")
LocalBroadcastManager.getInstance(this)
.registerReceiver(localReceiver, filter)
}
override fun onStop() {
super.onStop()
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(localReceiver)
}
Note本地广播只能动态注册,不能在清单里声明。因为它不经过系统,系统不知道它的存在。
Warning
LocalBroadcastManager已被官方标记为已废弃(deprecated)。官方推荐用LiveData、Flow或其他观察者模式替代。如果你的项目是新项目,建议直接用 Kotlin 的StateFlow/SharedFlow做应用内事件传递,比本地广播更现代。这里了解概念即可,老项目里可能还会碰到。
现代替代方案
既然本地广播废弃了,应用内通信该用什么?几个常见选择:
- 简单事件通知:用
SharedFlow发事件,UI 层用collectAsState收。 - 状态同步:用
StateFlow暴露状态,订阅者自动响应。 - 跨组件通信:用 ViewModel 共享数据(第 41 章会讲)。
// 一个简单的应用内事件总线
object AppEvents {
private val _events = MutableSharedFlow<String>()
val events = _events.asSharedFlow()
suspend fun emit(message: String) {
_events.emit(message)
}
}
广播权限
如果确实需要跨应用广播,又想限制谁能收发,可以用权限机制。
发送方限制接收方
发送时指定权限,只有声明了该权限的接收方才能收到:
context.sendBroadcast(
intent,
android.Manifest.permission.ACCESS_COARSE_LOCATION // 用系统权限举例
)
接收方清单里要声明对应权限:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
接收方限制发送方
反过来,接收方也可以要求发送方必须持有某权限:
<receiver
android:name=".MyReceiver"
android:permission="android.permission.ACCESS_COARSE_LOCATION"
android:exported="true">
<intent-filter>
<action android:name="com.example.app.PROTECTED_ACTION" />
</intent-filter>
</receiver>
这样只有持有该权限的应用才能给这个接收器发广播,恶意应用发不了。
Tip你也可以用
<permission>标签自定义权限,而不只用系统预置的。自定义权限能精确控制「只有我家的几个应用能互相通信」。
三种广播对比
| 特性 | 普通广播 | 有序广播 | 本地广播(已废弃) |
|---|---|---|---|
| 发送方法 | sendBroadcast() | sendOrderedBroadcast() | LocalBroadcastManager.sendBroadcast() |
| 接收顺序 | 并行,无序 | 按优先级顺序 | 应用内,无跨进程 |
| 可中断 | 否 | 是(abortBroadcast()) | 否 |
| 可传递结果 | 否 | 是 | 否 |
| 跨应用 | 是 | 是 | 否 |
| 安全性 | 低(需手动加权限) | 低 | 高 |
小结
有序广播适合需要按优先级处理、中途修改数据的场景,但 Android 16 后跨进程顺序不再保证。本地广播概念上很实用,但已废弃,新项目用 Flow 替代。跨应用广播务必加权限保护。日常开发里,绝大多数应用内通信用 Flow 就够了,广播主要用于接收系统事件。