01_Broadcast基础与分类_修订版
01 Broadcast 基础与分类
基于原 PDF 修订、联网校对并补充缺失内容
1. Broadcast 是什么
Broadcast 是 Android 中基于 Intent 的消息发布/订阅机制。发送方通过 Intent 表达“发生了什么”,接收方通过 IntentFilter 订阅感兴趣的 action。它既可以用于系统事件通知,也可以用于跨应用或应用内部的低耦合通知。
理解 Broadcast 时不要只按“无序/有序/本地”划分,更建议按三个维度看:作用范围、投递顺序、是否缓存最后一次事件。
| 维度 | 常见类型 | 重点 |
|---|---|---|
| 作用范围 | 系统广播、应用内广播、跨应用广播 | 由 Intent 的显式/隐式、package、permission、receiver exported 等共同决定。 |
| 投递顺序 | 普通广播、Ordered Broadcast | 普通广播不保证接收顺序;有序广播可传递 result,也可被 abort。 |
| 是否缓存 | 非粘性广播、Sticky Broadcast | 粘性广播会缓存 Intent 并重新投递给后注册者,但已被官方标为不推荐/废弃风险点。 |
2. 普通广播:sendBroadcast
普通广播使用 Context.sendBroadcast(intent)。它适合“通知型”事件:我只告诉大家某事发生了,不关心谁先收到,也不关心接收者返回什么。
- 多个接收者之间没有可依赖的执行顺序。
- 接收者不能把处理结果可靠地传给下一个接收者。
- 如果广播是隐式的,任何匹配的接收者都有机会收到;不要用它传敏感数据。
// Java:发送一个应用内约定 action 的普通广播
Intent intent = new Intent("com.example.app.ACTION_SYNC_FINISHED");
intent.setPackage(context.getPackageName()); // 限定在本应用包内,避免隐式广播外泄
intent.putExtra("success", true);
context.sendBroadcast(intent);
3. 有序广播:sendOrderedBroadcast
原 PDF 写成 sendOrderBroadcast,这是方法名错误;正确 API 是 sendOrderedBroadcast。Ordered Broadcast 会按照优先级和系统调度顺序逐个投递,前一个接收者可以通过 setResultCode、setResultData、setResultExtras 修改结果,也可以 abortBroadcast 阻止后续接收者继续接收。
Intent intent = new Intent("com.example.app.ACTION_CHECK");
intent.setPackage(context.getPackageName());
context.sendOrderedBroadcast(
intent,
null, // receiverPermission
null, // resultReceiver
null, // scheduler
Activity.RESULT_OK,
null,
null
);
- 适用:确实需要“前一个接收者影响后一个接收者”的场景。
- 不适用:普通应用内部事件总线、频繁状态同步、UI 层状态通知。
- 注意:有序广播是串行投递,滥用会影响性能和响应时间。
4. 显式广播与隐式广播
| 类型 | 写法 | 适用场景 | 风险/限制 |
|---|---|---|---|
| 显式广播 | setPackage() 或 setComponent() | 只发给指定应用或组件;内部通信;合作方 SDK 通信 | 更安全,但仍要校验来源与数据。 |
| 隐式广播 | 只设置 action,不指定包/组件 | 系统级事件通知;公开事件 | 可能被其他应用接收;Android 8.0 起 manifest 隐式广播受限。 |
实战建议:自定义业务广播尽量显式化。对外开放时使用自有包名前缀的 action,例如 com.example.pay.ACTION_RESULT,而不是 ACTION_RESULT 这种全局易冲突名称。
5. LocalBroadcastManager:只作为历史知识
原 PDF 把 LocalBroadcastManager 作为本地广播常规方案介绍,但现在它已被 AndroidX 官方完全废弃。它本质是应用内事件总线,并且使用 Intent 反而增加了不必要的限制。
- 如果是 ViewModel 到 UI:使用 LiveData、StateFlow、SharedFlow。
- 如果是模块间事件:优先定义清晰接口,必要时用 Kotlin Flow/RxJava/EventBus。
- 如果是跨进程:LocalBroadcastManager 不适合;应考虑 Binder/AIDL、ContentProvider、Messenger 或系统广播。
// Kotlin:用 SharedFlow 替代 LocalBroadcastManager 的一个简单例子
object AppEvents {
private val _events = MutableSharedFlow<AppEvent>(extraBufferCapacity = 1)
val events: SharedFlow<AppEvent> = _events
fun emit(event: AppEvent) {
_events.tryEmit(event)
}
}
sealed interface AppEvent {
data class SyncFinished(val success: Boolean) : AppEvent
}
6. Sticky Broadcast:补充概念
Sticky Broadcast 会把最后一次 Intent 缓存在系统中,后续注册的 receiver 也可能收到这条历史 Intent。这个设计存在敏感数据泄漏、伪造和篡改风险,官方已经把 sticky broadcast 标为不推荐使用。
- 不要在新业务中发送 sticky broadcast。
- 需要“当前状态”时,把状态放入数据库、DataStore、Repository 或系统服务查询接口。
- 系统广播中某些历史行为会表现得像 sticky,例如电量状态查询,但应用层不要仿造。
参考资料
- Android Developers - Broadcasts overview: https://developer.android.com/develop/background-work/background-tasks/broadcasts
- Android Developers - Implicit broadcast exceptions: https://developer.android.com/develop/background-work/background-tasks/broadcasts/broadcast-exceptions
- Android Developers - BroadcastReceiver API reference: https://developer.android.com/reference/android/content/BroadcastReceiver
- Android Developers - LocalBroadcastManager release notes: https://developer.android.com/jetpack/androidx/releases/localbroadcastmanager
- Android Developers - Android 14 behavior changes: https://developer.android.com/about/versions/14/behavior-changes-14
- Android Developers - Android 12 behavior changes: https://developer.android.com/about/versions/12/behavior-changes-12
- Android Developers - ConnectivityManager API reference: https://developer.android.com/reference/android/net/ConnectivityManager
- Android Developers - Sticky broadcasts risk: https://developer.android.com/privacy-and-security/risks/sticky-broadcast