一、 BroadcastReceiver 核心机制与考点
在面试中,面试官首先会询问你对BroadcastReceiver的基本理解。你需要清晰地区分静态注册与动态注册的区别,并深入理解其生命周期。
① 静态注册 (Static Registration)
在 AndroidManifest.xml 中声明。即使应用未启动,也能接收广播。适用于需要长期监听系统事件(如开机完成、网络变化)的场景。
- 优点:应用未运行也可接收。
- 缺点:启动慢,占用资源,高版本限制严格。
② 动态注册 (Dynamic Registration)
通过 registerReceiver() 代码注册。随Activity/Service生命周期变化,应用退出后自动失效。
- 优点:灵活,可注销,性能开销小。
- 缺点:应用未运行无法接收,需防止内存泄漏。
③ 生命周期管理
BroadcastReceiver 是短生命周期的组件。当广播到来时,系统调用 onReceive(),执行完毕后销毁。若在 onReceive() 中执行耗时操作,会导致ANR。
有序广播与普通广播的区别
这是面试中的经典对比题。普通广播(Normal Broadcast)是完全异步的,所有接收者几乎同时收到,无法截断。有序广播(Ordered Broadcast)则按照优先级顺序执行,高优先级的接收者可以先处理广播,甚至通过 abortBroadcast() 截断传播,或通过 setResult() 传递数据给下一个接收者。
二、 安全漏洞与导出问题
随着Android安全规范的收紧,BroadcastReceiver的安全性成为面试的高频考点。特别是“导出漏洞”和“权限控制”。
什么是导出漏洞?
如果 BroadcastReceiver 在 AndroidManifest.xml 中注册时未设置 android:exported="false"(Android 12+ 强制要求),或者显式设置为 true,则其他应用可以发送广播给该组件。
风险:攻击者可以发送恶意广播,触发你的 onReceive(),可能导致逻辑混乱、数据泄露甚至远程代码执行(如果处理不当)。
解决方案:
- 对于不对外开放的内部广播,务必设置
android:exported="false"。 - 对于需要对外开放的,必须使用
android:permission进行权限校验。
如何保护广播?
使用自定义权限是保护 BroadcastReceiver 的重要手段。
<permission android:name="com.example.MY_BROADCAST_PERMISSION"
android:protectionLevel="signature" />
<receiver android:name=".MyReceiver"
android:exported="true"
android:permission="com.example.MY_BROADCAST_PERMISSION">
<intent-filter>
<action android:name="com.example.CUSTOM_ACTION" />
</intent-filter>
</receiver>
这样,只有拥有 com.example.MY_BROADCAST_PERMISSION 权限的应用才能发送或接收该广播。
常见的内存泄漏场景
在动态注册时,如果忘记在 onDestroy() 中调用 unregisterReceiver(),会导致 BroadcastReceiver 实例持有 Activity 引用,从而引发内存泄漏。
最佳实践:
- 在
onCreate()注册,在onDestroy()注销。 - 使用局部内部类或静态内部类 + WeakReference 避免持有外部类引用。
- 考虑使用
LocalBroadcastManager(已废弃,推荐用 LiveData 或 Flow 替代)或ContextCompat.registerReceiver。
三、 Android 12 (API 31+) 及后续版本适配
从 Android 12 开始,Google 对隐式广播进行了严格限制。这是面试中区分初级与高级开发者的关键知识点。
后台限制
禁止在 AndroidManifest.xml 中注册大部分隐式广播。静态注册的 BroadcastReceiver 只能接收特定的系统广播(如开机、锁屏等)。
隐式广播移除
移除了超过30个隐式广播。应用若需监听这些广播,必须改为显式广播或使用其他替代方案(如 JobScheduler, WorkManager, ConnectivityManager.NetworkCallback)。
精确闹钟与蓝牙扫描
进一步限制了后台权限,BroadcastReceiver 若涉及敏感权限,需在清单中声明用途。
替代方案建议
当隐式广播不可用时,推荐使用以下替代方案:
- 网络状态: 使用
ConnectivityManager.NetworkCallback。 - 电量变化: 使用
BatteryManager的静态注册或LiveData。 - 应用间通信: 使用
ContentProvider或IPC机制。
四、 面试官最爱问的10个高频真题
以下整理了网络上求职者反馈频率最高的问题,并提供了深度解答思路。
| 序号 | 问题描述 | 核心考点 | 简答要点 |
|---|---|---|---|
| 1 | 静态注册和动态注册有什么区别? | 生命周期、注册方式 | 静态在Manifest,应用未启动也可收;动态在代码,随组件生命周期。 |
| 2 | 有序广播是如何实现的? | 广播类型、优先级 | 通过 android:priority 排序,高优先者先执行,可截断或修改结果。 |
| 3 | onReceive 中能执行耗时操作吗? | ANR、线程模型 | 不能。会阻塞主线程导致ANR。应启动 Service 或使用线程池。 |
| 4 | 什么是粘性广播?现在还能用吗? | 废弃API、安全 | 已废弃。Android 5.0+ 禁止使用 sendStickyBroadcast,因为存在安全风险。 |
| 5 | Android 12 对广播做了什么限制? | 版本适配、隐式广播 | 移除了大量隐式广播,强制要求显式广播或特定权限。 |
| 6 | 如何防止广播被恶意拦截? | 安全、权限 | 设置 android:exported="false" 或使用自定义 permission。 |
| 7 | LocalBroadcastManager 是什么?为什么被废弃? | 本地广播、架构演进 | 用于应用内广播,更安全高效。现被 LiveData/Flow 替代。 |
| 8 | 广播发送者和接收者可以在不同进程吗? | 跨进程通信、Binder | 可以。广播基于 Binder 机制,天然支持跨进程。 |
| 9 | 如何优化大量接收者的广播性能? | 性能优化、异步 | 使用普通广播(异步),减少优先级排序开销,避免在 onReceive 做重操作。 |
| 10 | 广播的优先级最大是多少? | 细节知识 | 最大 1000,最小 -1000。数字越大优先级越高。 |
总结
掌握 BroadcastReceiver 不仅是应对面试的必要条件,更是理解 Android 系统通信机制的基础。随着 Android 版本的迭代,其使用场景正在逐渐被更现代化的架构组件所补充或替代,但核心原理依然重要。希望本篇攻略能助你在面试中脱颖而出。