第二板块:Android 四大组件标准化学理 | 第九篇:BroadcastReceiver 事件分发与有序广播

第二板块:Android 四大组件标准化学理 | 第九篇:BroadcastReceiver 事件分发与有序广播

所属板块:第二板块 --- Android 四大组件标准化学理

前置知识:第八篇中的 Service 优先级、Binder IPC、AMS 调度机制

本篇定位 :BroadcastReceiver 是 Android 系统中最轻量级、最松散耦合 的组件。它不提供 UI,也不直接执行长时间任务,而是作为一个系统级事件的中转站(Event Hub) 。本篇将彻底拆解广播的异步分发模型AMS 中的队列管理机制静态注册与动态注册的权限鸿沟有序广播(Ordered Broadcast)的拦截与修改机制粘性广播(Sticky Broadcast)的历史遗留问题LocalBroadcastManager 的进程内通信本质 。我们将深入 ActivityManagerService (AMS)BroadcastQueue 的源码级逻辑,揭示广播为何被称为"冷启动炸弹"以及如何正确规避。


1. 核心结论先行(Thesis Statement)

BroadcastReceiver 是 Android 操作系统中用于接收系统或应用发出的异步消息(Intent)的组件。它不是线程 ,也不是服务 ,而是一个由系统服务(AMS)管理的、具有极短生命周期的、运行在主线程中的回调实体

  • Receiver 的本质 :一个事件监听器(Event Listener) 。它监听特定的 Intent 广播,并在接收到广播时执行一段简短的逻辑。
  • 分发模型异步发布-订阅模型(Pub-Sub)。发送者(Publisher)发出广播,AMS 作为中介(Broker)将广播分发给所有符合条件的接收者(Subscriber)。
  • 生命周期悖论 :Receiver 的 onReceive() 方法执行完毕后,系统会立即销毁 Receiver 实例。它不能执行耗时操作,否则会阻塞主线程导致 ANR。
  • 注册鸿沟静态注册 (Manifest)由系统唤醒,即使应用未运行也能接收;动态注册(Context.registerReceiver)依附于组件生命周期,组件销毁后失效。

2. BroadcastReceiver 的两种注册范式

2.1 静态注册(Manifest-declared)

AndroidManifest.xml 中声明 Receiver。这是系统级的注册方式。

学术定义

  • 常驻性:Receiver 信息在应用安装时由 PMS(PackageManagerService)解析并注册到系统中。
  • 唤醒能力:即使应用进程未运行,当广播到达时,AMS 会通过 Zygote 启动应用进程并实例化 Receiver。
  • 权限控制 :可以通过 android:permission 限制谁能发送广播给我。

Manifest 示例

xml 复制代码
<receiver
    android:name=".BootCompletedReceiver"
    android:enabled="true"
    android:exported="true"
    android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
    </intent-filter>
</receiver>

2.2 动态注册(Context-registered)

在代码中通过 Context.registerReceiver() 注册。这是应用级的注册方式。

学术定义

  • 临时性:Receiver 的生命周期与注册它的 Context(通常是 Activity 或 Service)绑定。
  • 灵活性:可以随时注册和注销,适合监听与 UI 状态相关的广播。
  • 无唤醒能力:如果应用进程已死,动态注册的 Receiver 无法接收广播。

代码示例(系统规范)

java 复制代码
public class MainActivity extends Activity {
    private MyReceiver receiver;

    @Override
    protected void onStart() {
        super.onStart();
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(receiver, filter);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unregisterReceiver(receiver); // 必须注销,否则内存泄漏
    }
}

2.3 两种注册方式的对比

维度 静态注册 动态注册
注册地点 AndroidManifest.xml Java/Kotlin 代码
生命周期 独立于应用进程 依附于 Context
唤醒能力 (冷启动应用) 不能
执行时机 系统随时可能唤醒 仅在应用运行时
适用场景 系统事件(开机、电量、网络) 应用内事件(UI 更新)

3. 广播的分类与分发算法

3.1 普通广播(Normal Broadcast)

异步发送,所有 Receiver 同时接收,无法被拦截或修改。

学术定义

  • 并行分发:AMS 将广播发送给所有符合条件的 Receiver,不保证顺序。
  • 不可控:发送者无法知道 Receiver 是否接收成功,也无法修改数据。

3.2 有序广播(Ordered Broadcast)

同步发送,Receiver 按优先级依次接收,可以拦截或修改数据。

学术定义

  • 串行分发 :Receiver 按 android:priority 从高到低依次执行。
  • 拦截机制 :高优先级的 Receiver 可以调用 abortBroadcast() 阻止广播继续向下传递。
  • 数据修改 :Receiver 可以通过 setResultExtras() 修改数据,供下一个 Receiver 使用。

Manifest 示例

xml 复制代码
<receiver android:name=".HighPriorityReceiver">
    <intent-filter android:priority="1000">
        <action android:name="com.example.MY_ORDERED_BROADCAST" />
    </intent-filter>
</receiver>
<receiver android:name=".LowPriorityReceiver">
    <intent-filter android:priority="-1000">
        <action android:name="com.example.MY_ORDERED_BROADCAST" />
    </intent-filter>
</receiver>

3.3 粘性广播(Sticky Broadcast)【已废弃】

Android 5.0 (L) 起废弃。它允许广播"粘"在系统上,后来注册的 Receiver 也能收到之前的广播。

学术定义

  • 历史缓存:AMS 会缓存最后一条粘性广播。
  • 安全风险:任何应用都可以接收敏感信息,已被禁止。

4. 广播的分发流程(AMS 源码级解析)

4.1 广播发送流程

sequenceDiagram participant Sender as 发送者进程 participant AMS as ActivityManagerService participant BQ as BroadcastQueue participant Receiver as 接收者进程 Sender->>AMS: sendBroadcast(intent) AMS->>AMS: 检查权限 (checkBroadcastFromSystem) AMS->>BQ: enqueueParallelBroadcastLocked() / enqueueOrderedBroadcastLocked() BQ->>BQ: 构建 BroadcastRecord BQ->>Receiver: scheduleReceiver() (Binder IPC) Receiver->>Receiver: 实例化 Receiver Receiver->>Receiver: onReceive() Receiver->>AMS: finishReceiver()

4.2 BroadcastQueue 的内部机制

AMS 中有两个 BroadcastQueue:

  1. Foreground Broadcast Queue:前台广播,优先级高,超时时间短(10秒)。
  2. Background Broadcast Queue:后台广播,优先级低,超时时间长(60秒)。

源码解析

java 复制代码
// ActivityManagerService.java
public void broadcastIntent(...) {
    // 1. 检查调用者权限
    enforceNotIsolatedCaller("broadcastIntent");

    // 2. 处理粘性广播
    if (sticky) {
        // ...
    }

    // 3. 选择队列
    BroadcastQueue queue = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0
            ? mFgBroadcastQueue : mBgBroadcastQueue;

    // 4. 入队
    queue.enqueueOrderedBroadcastLocked(r);
    queue.scheduleBroadcastsLocked();
}

4.3 BroadcastRecord 数据结构

java 复制代码
// com.android.server.am.BroadcastRecord
class BroadcastRecord extends Binder {
    final Intent intent;                 // 广播 Intent
    final ProcessRecord callerApp;       // 发送者进程
    final String[] requiredPermissions;  // 接收者需要的权限
    final int receiversSize;             // 接收者数量
    final ArrayList<BroadcastFilter> receivers; // 动态接收者
    final ResolveInfo[] resolveInfo;     // 静态接收者
    int nextReceiver;                    // 下一个要处理的接收者索引(有序广播用)
    boolean ordered;                    // 是否是有序广播
}

5. 广播的安全性机制

5.1 发送权限(Send Permission)

发送广播时可以指定权限,只有拥有该权限的应用才能接收。

java 复制代码
// 发送者
sendBroadcast(intent, "com.example.permission.MY_PERMISSION");

// 接收者 Manifest
<uses-permission android:name="com.example.permission.MY_PERMISSION" />

5.2 接收权限(Receive Permission)

在 Manifest 中声明 Receiver 时指定权限,只有拥有该权限的发送者才能发送广播给我。

xml 复制代码
<receiver
    android:name=".MyReceiver"
    android:permission="com.example.permission.ANOTHER_PERMISSION">
    <intent-filter>
        <action android:name="com.example.MY_ACTION" />
    </intent-filter>
</receiver>

5.3 LocalBroadcastManager(进程内安全广播)

LocalBroadcastManager 是 Support Library 提供的进程内广播 工具。它不使用 Binder IPC,也不通过 AMS,而是直接在应用进程内分发。

学术定义

  • 安全性:广播数据不会离开应用进程,不会被其他应用截获。
  • 效率:避免了 IPC 开销,速度更快。
  • 现状 :已被 LiveDataRxJava 等响应式编程库取代,但在理解广播机制时仍具学术价值。

6. 广播的陷阱与系统限制

6.1 ANR 风险

onReceive() 运行在主线程,且只有 10 秒 (前台广播) 或 60 秒(后台广播)的执行时间。

学术定义

  • ANR(Application Not Responding) :如果 onReceive() 执行超过规定时间,系统会弹出 ANR 对话框。
  • 禁忌绝对不能在 onReceive() 中执行网络请求、数据库读写、文件 IO 或睡眠操作

6.2 广播延迟与排队

当系统繁忙时,广播可能会被延迟。特别是在 Android 8.0 (O) 之后,系统对后台广播进行了严格限制。

Android 8.0+ 的限制

  • 后台执行限制:应用在后台时,无法注册隐式广播的静态 Receiver(部分系统广播除外,如开机广播)。
  • 原因:防止应用滥用广播在后台唤醒,消耗电量。

6.3 替代方案

由于广播的局限性,现代 Android 开发推荐使用以下方案:

场景 推荐方案 学术理由
应用内通信 LiveData / RxJava / Flow 响应式编程,解耦更彻底,无 IPC 开销。
跨进程通信 Messenger / AIDL 需要双向通信或复杂数据结构时。
后台任务 WorkManager / JobScheduler 系统调度,省电,符合后台限制。
系统事件 静态注册广播 唯一合法场景,如开机、电量变化。

7. 关键源码解析:广播的匹配算法

AMS 如何找到符合条件的 Receiver?

java 复制代码
// PackageManagerService.java
public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
    // 1. 查询静态 Receiver (Manifest)
    List<ResolveInfo> receivers = mReceivers.queryIntent(intent, resolvedType, flags, userId);

    // 2. 过滤权限
    for (ResolveInfo ri : receivers) {
        if (!grantImplicitAccess(userId, ri, uid, owningUid, false)) {
            continue; // 权限不足,过滤掉
        }
    }
    return receivers;
}

8. 广播的冷启动效应与性能影响

8.1 冷启动炸弹(Cold Start Bomb)

静态注册的 Receiver 具有唤醒能力,这意味着一个广播可以启动一个已经死亡的应用进程。

学术定义

  • 进程创建开销:每次唤醒都需要 Zygote fork 新进程,加载 ART 虚拟机,初始化 Application。
  • 累积效应:如果多个应用都监听同一个高频广播(如网络变化),会导致系统频繁创建和销毁进程,造成严重的性能损耗和电量消耗。

8.2 广播的序列化执行

即使是普通广播,在同一个应用进程中,Receiver 的 onReceive() 也是串行执行的。如果一个 Receiver 执行时间过长,会阻塞后续 Receiver 的执行。


9. 关键数据结构与源码定义(续)

9.1 BroadcastFilter(动态注册记录)

java 复制代码
// com.android.server.am.BroadcastFilter
class BroadcastFilter extends IntentFilter {
    final String packageName;
    final String receiverClassName;
    final int owningUid;
    final int owningPid;
    final boolean instantApp;
}

9.2 ReceiverList(Receiver 列表)

java 复制代码
// com.android.server.am.ReceiverList
class ReceiverList extends ArrayList<BroadcastFilter> {
    final ProcessRecord app;            // 所属进程
    final int pid;                     // 进程 ID
    final int uid;                     // 用户 ID
    final String packageName;          // 包名
}

10. 本篇总结(Knowledge Closure)

关键点 纯学术定义
Receiver 的本质 由 AMS 管理的事件监听器,生命周期极短,运行在主线程。
注册范式 静态注册(系统级,可唤醒)与动态注册(应用级,依附生命周期)。
分发模型 异步 Pub-Sub 模型,有序广播提供拦截和修改能力。
安全性 通过发送权限和接收权限实现双向保护。
系统限制 Android 8.0+ 严格限制后台静态广播,防止滥用。
性能陷阱 冷启动开销大,执行时间长会导致 ANR。

下一篇预告第二板块:Android 四大组件标准化学理 | 第十篇:ContentProvider 数据共享与 SQLite 引擎

相关推荐
杊页1 小时前
第二板块:Android 四大组件标准化学理 | 第八篇:Service 后台执行实体与优先级
android
Chelsea05221 小时前
PC浏览器在线调试 Android 浏览器教程-chrome://inspect/#devices
android·前端·chrome
我命由我123451 小时前
Android 开发问题:EditText 控件的 android:imeOptions=“actionDone“ 属性不生效
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
我命由我123451 小时前
Android 开发问题:获取到的 Android ID 发生了变化
android·java·开发语言·java-ee·android studio·android jetpack·android runtime
恋猫de小郭1 小时前
由于 iOS 26 的键盘变化,Flutter 又要重构键盘区域逻辑
android·前端·flutter
我命由我123452 小时前
Android 开发问题:Unable to find explicit activity class
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
我命由我123452 小时前
Android 开发问题:全局的主题颜色设置,导致 CheckBox 控件在勾选状态下不显示样式
android·java·开发语言·java-ee·intellij-idea·intellij idea·android jetpack
Kapaseker2 小时前
一个丝滑的数字计数器,讲清楚 AnimatedContent 怎么用
android·kotlin
故渊at2 小时前
第十六板块:Android 综合实战与架构复盘 | 第三十七篇:从开机到桌面点击的全链路架构复盘
android·架构·冷启动·热启动·架构复盘·开机到桌面