broadcast intent

broadcast intent:保留第四版正文机制,以所有者—状态—结果合同、事件轨迹和章专属故障完成可重放验收。

学习目标

  • 能沿“broadcast intent”的用户事件解释Android组件、状态所有者、线程与销毁边界。
  • 能围绕“理解 Android 的广播机制:系统广播、自定义广播、动态注册与静态注册的区别,以及 Android 8.0+ 对隐式广播的限制和现代替代方案。”改出一个可运行结果,并用前后状态而非组件数量验收。
  • 能在旋转、进程重建、拒权、离线或无效输入中选择适用反例,定位首个状态分叉。
  • 能用Intent合同、解析目标、权限、返回结果和重复副作用独立重放结论,并标明第四版机制与现代targetSdk政策的边界。

为什么需要"广播"?

你手机里装的 App 互不认识,但它们需要在一些事情发生时知道该怎么做。比如:系统连上了 Wi-Fi——下载管理器要开始下载离线地图、音乐 App 可能要切换音质、你的 App 要触发一次数据同步。如果每个 App 都自己去轮询"Wi-Fi 连上了吗?",整个系统会被轮询搞垮。

Android 的广播机制就是为此设计的:系统是唯一的"大喇叭",发生什么事它喊一声,谁需要听就自己来注册。喊的人不管有多少听众,听众也不关心还有谁在听。这种发布-订阅的松耦合模式,就是 Android 广播的核心思想。

这章要解决的核心问题:怎么让你的 App 感知到手机系统里正在发生的事(Wi-Fi 变化、电量低、开屏关屏),以及怎么用广播让 App 内部各组件解耦通信。

广播接收器的基本使用

什么是 BroadcastReceiver

是 Android 四大组件中最轻量的一个。它的作用非常简单——定义对某个事件感兴趣的"耳朵"

一个 BroadcastReceiver 只需要实现一个方法:

class MyReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // 收到广播时执行这里的代码
        when (intent.action) {
            Intent.ACTION_POWER_CONNECTED -> {
                // 充电器插上了
            }
            Intent.ACTION_BATTERY_LOW -> {
                // 电量低了
            }
        }
    }
}

两种注册方式:动态 vs 静态

动态注册(代码中)静态注册(Manifest 中)
注册方式registerReceiver(receiver, filter)<receiver> 标签声明
生命周期跟随 Activity/Service,必须手动 unregisterReceiver随应用安装生效,App 未启动也能接收
Android 8.0+ 限制大部分广播仍可用绝大多数隐式广播不再发送给静态注册的 Receiver
典型场景App 在前台时感知事件开机自动启动(仅少数豁免广播)

动态注册示例

class MainActivity : AppCompatActivity() {
    private lateinit var receiver: BroadcastReceiver
    private var isRegistered = false
 
    override fun onResume() {
        super.onResume()
        receiver = MyReceiver()
        val filter = IntentFilter().apply {
            addAction(Intent.ACTION_BATTERY_LOW)
            addAction(Intent.ACTION_BATTERY_OKAY)
        }
        registerReceiver(receiver, filter)
        isRegistered = true
    }
 
    override fun onPause() {
        super.onPause()
        if (isRegistered) {
            unregisterReceiver(receiver)
            isRegistered = false
        }
    }
}

动态注册的金科玉律:在哪注册就在对称位置注销——onResume 注册、onPause 注销是最常见的模式。忘了注销 = 泄漏 BroadcastReceiver,系统会在日志里警告你。

静态注册示例(仅在少数场景有效)

<receiver
    android:name=".BootReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

开机广播 BOOT_COMPLETED 是少数几个在 Android 8.0+ 仍能通过静态注册接收的广播之一。

动手看:一条广播从"发出"到"被所有接收者处理"

猜一猜:同一个 App 里注册了 3 个 Receiver 监听同一个广播,它们接收的顺序是什么?

分步1 / 5

① 系统事件触发广播

系统检测到电池电量低于 15%,BatteryService 构造一个 Intent(Intent.ACTION_BATTERY_LOW),调用 sendBroadcast(intent)。这个 Intent 的 action 就是 BATTERY_LOW

可交互
发送者 AppsendBroadcast(intent)系统广播总线ActivityManager 分发ReceiverA动态 registerReceiverReceiverB静态 manifest 声明ReceiverC静态 manifest 声明广播 Intentaction = DATA_LOADED或 BOOT_COMPLETED收集所有匹配 action 的 Receiver普通广播:sendBroadcast → 并行、无序有序广播:sendOrderedBroadcast → 按 priority 串行、可 abort 中断Android 8.0+:大部分隐式广播不能再静态 manifest 注册(需动态)① 发出② 收集 · ③ 分叉④ onReceive

第 1 / 4 步 · ① 发送者 App 调 sendBroadcast(intent)(action = 自定义如 DATA_LOADED,或系统广播如 BOOT_COMPLETED)

点击播放,看一条广播如何从发送者发出、经系统总线收集注册者、并行分叉(fan-out)到多个 Receiver、最后触发各自 onReceive;可暂停、单步、拖进度逐帧观察。

广播 Intent 分发(fan-out):发送者 sendBroadcast → 系统广播总线收集所有注册了该 action 的 Receiver(动态 + 静态)→ 广播令牌并行分叉同时流向多个 Receiver → 各 onReceive 处理。普通广播并行无序;有序广播按 priority 串行、可中断。

代码逐段拆解:自定义广播与 App 内通信

发送自定义广播

// 发送方
val intent = Intent("com.example.app.DATA_LOADED").apply {
    putExtra("record_count", 42)
    `package` = packageName  // Android 8.0+ 推荐:限制广播只在本 App 内接收
}
sendBroadcast(intent)

接收自定义广播(动态注册)

// 接收方(在 Activity/Fragment 中)
val filter = IntentFilter("com.example.app.DATA_LOADED")
registerReceiver(object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val count = intent.getIntExtra("record_count", 0)
        updateUI(count)
    }
}, filter)

有序广播的使用场景

// 发送有序广播
sendOrderedBroadcast(
    Intent("com.example.ACTION_CHECK"),
    null,                               // 无需额外权限
    null,                               // 结果接收者(可选)
    null,                               // Handler(可选)
    Activity.RESULT_OK,                 // 初始结果码
    "OK",                               // 初始结果数据
    null                                // 初始结果附加数据
)
 
// 在 Receiver 中处理并传递结果
class CheckReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (checkFailed()) {
            resultCode = Activity.RESULT_CANCELED
            resultData = "Check failed at step 1"
        }
        // 如果没调 abortBroadcast(),下一个 Receiver 继续执行
    }
}

有序广播的经典场景:级联校验——Receiver A 检查权限 → Receiver B 检查网络 → Receiver C 才开始实际工作。任何一环失败可阻断后续。

容易踩的坑

小结

  • BroadcastReceiver 是 Android 发布-订阅模式的核心实现:系统/App 发送广播,注册了匹配 IntentFilter 的 Receiver 接收处理
  • 动态注册(代码中 registerReceiver)灵活但需手动注销;静态注册(Manifest 中声明)Android 8.0+ 对隐式广播有严格限制
  • sendBroadcast 并行分发,顺序不保证;sendOrderedBroadcast 按 priority 串行执行,可逐级传递结果或中断
  • LocalBroadcastManager 已被废弃——App 内通信推荐用 LiveData / Flow / EventBus 等现代方案
  • App 进入 Standby 模式后,后台的广播接收和网络请求会被系统延迟批处理,这是 Android 6.0+ 的 Doze 机制

练习

问题 1:“第28章 Broadcast Intents”覆盖哪些正式节点和项目主线?

问题 2:怎样建立本页最小可执行实验?

问题 3:为什么只在正常点击路径运行不能证明完成?

问题 4:怎样设计能推翻当前实现的反例?

问题 5:从第4版语境迁移到现代目标SDK时如何控制变量?

问题 6:本页达到独立交接标准需要什么?

名词解释

名词解释

本章出现的专业名词,用大白话再讲一遍。

BroadcastReceiver(广播接收器)

Android 四大组件中最轻量的一个——它的唯一工作就是接收广播并处理。你可以把它理解成一个"事件订阅器":声明你对哪些事件感兴趣,事件发生时系统调你的 onReceive() 来通知你。这是 Android 发布-订阅模式的核心实现。详见本章"什么是 BroadcastReceiver"一节。

IntentFilter

一组过滤规则,声明 BroadcastReceiver 关心哪些广播。通过 addAction() 添加 action 字符串来匹配广播。系统通过对比广播的 action 与 IntentFilter 中声明的 action 来决定是否唤醒你的 Receiver。详见本章"动态注册示例"一节。

有序广播(Ordered Broadcast)

一种按接收者优先级串行分发的广播模式。接收者通过 android:priority 从高到低一个接一个执行。每个接收者可以修改结果数据传递给下一个,也可以完全截断广播(abortBroadcast())。适合"级联校验"等需要顺序控制的场景。详见本章"有序广播"一节。

隐式广播(Implicit Broadcast)

不以特定包名为目标的广播——系统把 Intent 发给所有声明了匹配 IntentFilter 的 Receiver。Android 8.0+ 大幅限制隐式广播,绝大多数不再唤醒静态注册的 Receiver。这是为省电设计的举措。详见本章"容易踩的坑"一节。

“broadcast intent”不使用未获授权的纸书正文;InformIT出版信息授权电子版完整目录只用于确认第四版32章、269个正式目录节点和时代语境,第四版官方勘误用于识别工具链变更。下列中文解释、图示、交互、代码与练习均为独立教学重写,平台行为再以Android Developers的一手文档复核。

为什么“broadcast intent”必须回到可观察状态

“broadcast intent”的学习结果不是记住类名,而是能预测“理解 Android 的广播机制:系统广播、自定义广播、动态注册与静态注册的区别,以及 Android 8.0+ 对隐式广播的限制和现代替代方案。”在一次输入、一次重建和一次失败中的不同状态,并指出哪条Android合同产生差异。

第四版机制逐项深读

28. Broadcast Intents

在“broadcast intent”中,“28. Broadcast Intents”把事件发送给匹配Receiver;静态与动态注册、导出权限和接收器短生命周期决定可达性,长任务应转交受约束后台工作。

Regular Intents vs Broadcast Intents

在“broadcast intent”中,“Regular Intents vs Broadcast Intents”把事件发送给匹配Receiver;静态与动态注册、导出权限和接收器短生命周期决定可达性,长任务应转交受约束后台工作。

Filtering Foreground Notifications

在“broadcast intent”中,分析“Filtering Foreground Notifications”先冻结设备API、targetSdk和输入,再沿回调与数据流寻找首个状态分叉,不能只描述最终页面。

Receivers and Long-Running Tasks

在“broadcast intent”中,“Receivers and Long-Running Tasks”跨应用边界时只授予完成任务所需的URI与组件权限,并在日志中移除联系人等个人信息。

For the More Curious: Local Events

在“broadcast intent”中,“For the More Curious: Local Events”把事件发送给匹配Receiver;静态与动态注册、导出权限和接收器短生命周期决定可达性,长任务应转交受约束后台工作。

For the More Curious: Limitations on Broadcast Receivers

在“broadcast intent”中,“For the More Curious: Limitations on Broadcast Receivers”把事件发送给匹配Receiver;静态与动态注册、导出权限和接收器短生命周期决定可达性,长任务应转交受约束后台工作。

For the More Curious: Detecting the Visibility of Your Fragment

在“broadcast intent”中,“For the More Curious: Detecting the Visibility of Your Fragment”的容器替换不是简单换画面;状态保存后提交、重复tag与嵌套管理器都会改变恢复结果。

“broadcast intent”验收回顾

“broadcast intent”只有在Intent合同、解析目标、权限、返回结果和重复副作用能够从相同基线再次得到相同断言时才通过;第四版机制与现代平台政策分别记录,不用新API名称掩盖旧行为。

← 上一页:WorkManager · 下一页:网页浏览 →

章专属可重放状态实验

先预测“前后台切换、动态注册、发送广播与进程回收”发生后,BroadcastReceiver、注册作用域与 WorkManager应怎样改变action、extras、导出/权限、接收窗口和转交工作;再操作三个实验。第四版示例与当前 Android 政策分别记录,实验不把新 API 名称倒填为原书内容。

实验一:所有者—状态—结果合同

选择任一正式目录节点和正常/边界场景,检查它是否真的进入本章状态合同。目录标题只有同时出现在解释、可视状态和交付证据中才算覆盖。

Owner · state · observable result

broadcast intent:状态合同

区分普通 Intent 与广播,并把长任务从 Receiver 转交受约束工作

验证场景

第四版正式目录节点

broadcast-intents · 正常任务

28. Broadcast Intents固定 SDK、设备配置和初始状态,触发“前后台切换、动态注册、发送广播与进程回收”

状态所有者BroadcastReceiver、注册作用域与 WorkManager
受控状态action、extras、导出/权限、接收窗口和转交工作
触发事件前后台切换、动态注册、发送广播与进程回收

冻结入口:28. Broadcast Intents

记录BroadcastReceiver、注册作用域与 WorkManager的初始action、extras、导出/权限、接收窗口和转交工作

观察:注册日志、发送方 UID、权限、onReceive 时长和转交 WorkInfo中的“28. Broadcast Intents”轨迹

预期:由BroadcastReceiver、注册作用域与 WorkManager提交action、extras、导出/权限、接收窗口和转交工作,并持续满足“Receiver 只做短处理,外部广播受权限与导出边界约束”

实验二:事件与生命周期轨迹

沿五次转换逐步执行“前后台切换、动态注册、发送广播与进程回收”。每一步只允许BroadcastReceiver、注册作用域与 WorkManager按职责提交状态,并持续核对“Receiver 只做短处理,外部广播受权限与导出边界约束”。

Deterministic event replay

broadcast intent:事件轨迹

选择一次状态转换1 / 5

不变量:Receiver 只做短处理,外部广播受权限与导出边界约束

交付证据:注册日志、发送方 UID、权限、onReceive 时长和转交 WorkInfo

实验三:章专属反例与同输入恢复

注入“在 onReceive 中同步联网,超过生命周期窗口被系统终止”,保存第一个偏离点;撤销后以完全相同的 SDK、设备状态和用户事件重放。只有注册日志、发送方 UID、权限、onReceive 时长和转交 WorkInfo一起恢复才算修复。

Fault · cancel · restore

broadcast intent:反例与恢复

故障:在 onReceive 中同步联网,超过生命周期窗口被系统终止

1. 冻结输入一致

第 1 次使用相同 SDK、设备配置、初始状态与用户事件

2. 注入边界一致

保持正常输入不变,仅注入“在 onReceive 中同步联网,超过生命周期窗口被系统终止”

3. 检查所有者一致

Receiver 只做短处理,外部广播受权限与导出边界约束

4. 核对结果一致

注册日志、发送方 UID、权限、onReceive 时长和转交 WorkInfo

讨论

评论区加载中…