在 Android 四大组件中,BroadcastReceiver(广播接收器)是用于接收和响应系统或应用发出的广播事件的组件。它采用发布 - 订阅模式,能实现跨组件、跨进程的通信,是 Android 系统中解耦组件间交互的重要方式。本文将从基本概念、分类、生命周期、使用方式到实战案例全面解析 BroadcastReceiver,并整理高频面试题,助力开发者夯实基础。
一、BroadcastReceiver 核心概念:什么是广播?
BroadcastReceiver(简称 “广播”)是 Android 系统中一种全局的事件通知机制,其核心作用是接收并处理来自系统或其他应用的广播消息。例如:
- 系统广播:开机完成、网络状态变化、电池电量低、屏幕点亮 / 熄灭等;
- 应用广播:应用内自定义事件(如下载完成、数据更新)、跨应用通知等。
广播的核心特点:
- 松耦合:发送者无需知道接收者的存在,接收者只需关注自己关心的广播类型;
- 全局性:同一广播可被多个接收器同时接收(一对多通信);
- 生命周期短暂:Receiver 接收事件后,
onReceive()
方法执行完毕即销毁,无法执行耗时操作(否则会导致 ANR)。
二、BroadcastReceiver 的分类:按发送方式划分
根据广播的发送方式和传播特性,可分为以下 4 类,核心差异在于传播范围、优先级和是否可被拦截:
广播类型 | 发送方法 | 特点 | 适用场景 |
---|---|---|---|
普通广播(Normal) | sendBroadcast() | 异步传播,所有接收器无序接收,无法拦截或修改数据,效率高 | 一般通知(如下载完成) |
有序广播(Ordered) | sendOrderedBroadcast() | 同步传播,按优先级排序接收,高优先级接收器可拦截广播或修改数据 | 需要优先级处理的场景(如权限验证) |
本地广播(Local) | LocalBroadcastManager.sendBroadcast() | 仅在应用内传播,无法跨进程,安全性高,效率高 | 应用内组件通信(如 Fragment 通知 Activity) |
粘性广播(Sticky) | sendStickyBroadcast() | 发送后会被系统保存,新注册的接收器可接收历史广播(已过时,API 21 起废弃) | 需保留最新状态的场景(如电量变化) |
1. 普通广播(Normal Broadcast)
最常用的广播类型,发送后所有接收器同时接收(无顺序),且无法阻止其他接收器接收,也不能修改广播数据。
// 发送普通广播
Intent intent = new Intent("com.example.MY_NORMAL_BROADCAST");
intent.putExtra("data", "这是普通广播的数据");
sendBroadcast(intent);
2. 有序广播(Ordered Broadcast)
广播按优先级(priority
,范围 - 1000~1000,值越高优先级越高)依次发送给接收器。高优先级接收器可:
- 通过
abortBroadcast()
拦截广播(低优先级接收器无法接收); - 通过
setResultData()
修改广播数据(低优先级接收器接收修改后的数据)。
// 发送有序广播(需权限时可添加第二个参数,如null表示无需权限)
Intent intent = new Intent("com.example.MY_ORDERED_BROADCAST");
intent.putExtra("data", "原始数据");
sendOrderedBroadcast(intent, null);
在 Manifest 中注册时指定优先级:
<receiver
android:name=".HighPriorityReceiver"
android:exported="false">
<intent-filter android:priority="100"> <!-- 高优先级 -->
<action android:name="com.example.MY_ORDERED_BROADCAST" />
</intent-filter>
</receiver>
<receiver
android:name=".LowPriorityReceiver"
android:exported="false">
<intent-filter android:priority="50"> <!-- 低优先级 -->
<action android:name="com.example.MY_ORDERED_BROADCAST" />
</intent-filter>
</receiver>
高优先级接收器拦截或修改数据:
public class HighPriorityReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 获取原始数据
String data = intent.getStringExtra("data"); // 输出:原始数据
// 修改数据(低优先级接收器会收到修改后的数据)
intent.putExtra("data", "修改后的数据");
setResultData("额外结果数据"); // 可通过getResultData()获取
// 拦截广播(低优先级接收器无法接收)
// abortBroadcast();
}
}
3. 本地广播(Local Broadcast)
仅在当前应用内传播,无法跨进程,因此:
- 安全性更高(避免其他应用监听或发送恶意广播);
- 效率更高(无需跨进程通信)。
需通过LocalBroadcastManager
管理,用法与普通广播类似:
// 1. 获取LocalBroadcastManager实例
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
// 2. 注册本地广播接收器
IntentFilter filter = new IntentFilter("com.example.MY_LOCAL_BROADCAST");
localBroadcastManager.registerReceiver(localReceiver, filter);
// 3. 发送本地广播
Intent intent = new Intent("com.example.MY_LOCAL_BROADCAST");
intent.putExtra("msg", "这是本地广播");
localBroadcastManager.sendBroadcast(intent);
// 4. 注销接收器(必须在组件销毁时执行)
@Override
protected void onDestroy() {
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
// 本地广播接收器
private BroadcastReceiver localReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.d("LocalBroadcast", msg); // 输出:这是本地广播
}
};
4. 粘性广播(Sticky Broadcast)
已过时(Android 5.0 API 21 起废弃),原因是安全性差且容易导致内存泄漏。其特点是广播发送后会被系统保存,当新的接收器注册时,可立即收到最近一次的粘性广播。
替代方案:使用LocalBroadcastManager
的本地广播,或通过SharedPreferences
/ 数据库保存状态,新组件启动时主动读取。
三、BroadcastReceiver 的注册方式:静态与动态
广播接收器必须 “注册” 后才能接收广播,注册方式分为静态注册(Manifest 中声明)和动态注册(代码中注册),两者适用场景不同。
1. 静态注册:Manifest 声明(常驻型)
在AndroidManifest.xml
中声明接收器,应用安装后即生效,即使应用进程未启动,也能接收广播(系统会唤醒进程)。
适用场景:
- 接收系统广播(如开机启动、网络变化);
- 需在应用未运行时响应的事件。
示例:注册网络状态变化接收器
<!-- 1. 声明权限(网络状态需要ACCESS_NETWORK_STATE权限) -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 2. 注册广播接收器 -->
<receiver
android:name=".NetworkChangeReceiver"
android:exported="true"> <!-- 允许接收外部应用广播 -->
<intent-filter>
<!-- 系统网络状态变化的action -->
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
接收器实现:
public class NetworkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 检查网络状态
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (isConnected) {
Toast.makeText(context, "网络已连接", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "网络已断开", Toast.LENGTH_SHORT).show();
}
}
}
注意:
- Android 7.0(API 24)后,部分系统广播(如
CONNECTIVITY_CHANGE
)不再支持静态注册,需改用动态注册或请求权限; android:exported="true"
表示允许接收其他应用的广播,若仅接收本应用广播,需设为false
(安全最佳实践)。
2. 动态注册:代码中注册(临时型)
在代码(如 Activity、Service)中通过registerReceiver()
注册,随组件生命周期生效,组件销毁前必须调用unregisterReceiver()
注销,否则会导致内存泄漏。
适用场景:
- 仅在组件运行时需要接收广播(如 Activity 可见时);
- 接收 Android 7.0 + 后不支持静态注册的系统广播。
示例:在 Activity 中动态注册时间变化广播
public class MainActivity extends AppCompatActivity {
private TimeChangeReceiver timeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1. 创建接收器实例
timeReceiver = new TimeChangeReceiver();
// 2. 创建IntentFilter,指定接收的action(系统时间变化)
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK); // 每分钟触发一次
}
@Override
protected void onResume() {
super.onResume();
// 3. 注册广播接收器(在onResume()中注册,与生命周期同步)
registerReceiver(timeReceiver, filter);
}
@Override
protected void onPause() {
super.onPause();
// 4. 注销广播接收器(在onPause()中注销,避免内存泄漏)
unregisterReceiver(timeReceiver);
}
// 时间变化接收器
private class TimeChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_TIME_TICK.equals(intent.getAction())) {
Log.d("TimeChange", "当前时间:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
}
}
注意:
- 动态注册的接收器优先级高于静态注册(同优先级下);
- 必须在组件销毁前注销,否则会抛出
IllegalArgumentException: Receiver not registered
异常。
四、BroadcastReceiver 的生命周期与注意事项
1. 生命周期
BroadcastReceiver 的生命周期极其短暂:
- 当广播事件触发时,系统创建 Receiver 实例;
- 调用
onReceive(Context, Intent)
方法处理事件; - 方法执行完毕后,Receiver 实例立即被销毁(生命周期结束)。
核心限制:onReceive()
方法必须在10 秒内执行完毕,否则会触发 ANR(Application Not Responding)。因此:
- 不能在
onReceive()
中执行耗时操作(如下载、数据库写入); - 若需处理耗时任务,需通过
IntentService
(过时)、WorkManager
或启动 Service 处理(注意:Android 8.0 + 启动 Service 需用前台 Service)。
2. 注意事项
(1)避免 ANR 的正确做法
若onReceive()
中需执行耗时操作,应启动后台任务:
@Override
public void onReceive(Context context, Intent intent) {
// 错误:直接执行耗时操作(会ANR)
// doLongTimeTask();
// 正确:启动Service处理(Android 8.0+需用前台Service)
Intent serviceIntent = new Intent(context, MyBackgroundService.class);
context.startService(serviceIntent);
// 或使用WorkManager(推荐)
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(MyWorker.class).build();
WorkManager.getInstance(context).enqueue(work);
}
(2)静态注册的局限性
Android 3.1 + 引入 “应用安装后首次启动前不接收广播” 的机制,避免恶意应用通过广播唤醒未启动的应用。若需接收广播,需用户至少启动一次应用。
(3)权限控制
- 发送广播时可指定权限:只有声明了该权限的应用才能接收;
- 接收广播时可指定权限:只有拥有该权限的应用发送的广播才能被接收。
示例:发送带权限的广播
// 发送时指定权限(需在Manifest中声明该权限)
sendBroadcast(intent, "com.example.PERMISSION_SEND_BROADCAST");
在 Manifest 中声明权限并接收:
<!-- 声明权限 -->
<permission android:name="com.example.PERMISSION_SEND_BROADCAST" android:protectionLevel="normal" />
<uses-permission android:name="com.example.PERMISSION_SEND_BROADCAST" />
<!-- 接收时限制发送者必须有该权限 -->
<receiver
android:name=".MyReceiver"
android:permission="com.example.PERMISSION_SEND_BROADCAST"> <!-- 仅接收有此权限的广播 -->
<intent-filter>
<action android:name="com.example.MY_BROADCAST" />
</intent-filter>
</receiver>
五、系统常用广播 Action
Android 系统内置了大量广播 Action,用于通知系统状态变化,常用的有:
Action | 含义 | 所需权限 | 备注(是否支持静态注册) |
---|---|---|---|
android.intent.action.BOOT_COMPLETED | 系统开机完成 | RECEIVE_BOOT_COMPLETED | 支持(需权限) |
android.net.conn.CONNECTIVITY_CHANGE | 网络状态变化 | ACCESS_NETWORK_STATE | Android 7.0 + 仅支持动态注册 |
android.intent.action.BATTERY_LOW | 电池电量低 | 无 | 支持 |
android.intent.action.SCREEN_ON | 屏幕点亮 | 无 | 仅支持动态注册 |
android.intent.action.SCREEN_OFF | 屏幕熄灭 | 无 | 仅支持动态注册 |
android.intent.action.PACKAGE_INSTALLED | 应用安装完成 | 无 | 需指定 dataScheme 为 "package" |
android.intent.action.TIME_TICK | 每分钟时间更新 | 无 | 仅支持动态注册 |
六、BroadcastReceiver 高频面试题(含答案)
1. BroadcastReceiver 的两种注册方式有何区别?
对比维度 | 静态注册(Manifest) | 动态注册(代码中) |
---|---|---|
生效时机 | 应用安装后立即生效 | 组件(如 Activity)运行时注册后生效 |
生命周期依赖 | 不依赖组件,应用未运行也能接收 | 依赖组件,组件销毁前必须注销 |
适用场景 | 系统级事件(如开机启动) | 组件运行时的临时事件(如屏幕状态变化) |
灵活性 | 固定配置,无法动态修改过滤规则 | 可动态修改 IntentFilter,灵活性高 |
系统限制 | Android 7.0 + 对部分系统广播有限制 | 无此限制,支持所有广播 |
2. 普通广播与有序广播的区别?
- 传播方式:普通广播异步并发,所有接收器同时接收;有序广播同步串行,按优先级依次接收。
- 拦截与修改:普通广播无法拦截或修改数据;有序广播高优先级接收器可通过
abortBroadcast()
拦截,或通过setResultData()
修改数据。 - 效率:普通广播效率更高(无顺序等待);有序广播因同步执行,效率较低。
- 发送方法:普通广播用
sendBroadcast()
;有序广播用sendOrderedBroadcast()
。
3. 为什么 BroadcastReceiver 的 onReceive () 方法不能执行耗时操作?如何解决?
- 原因:
onReceive()
运行在主线程(UI 线程),若执行耗时操作(超过 10 秒)会导致 ANR;且 Receiver 生命周期短暂,方法执行完毕后实例会被销毁,耗时任务可能被中断。 - 解决方式:
- 启动前台 Service(Android 8.0 + 必须用前台 Service,避免被系统限制)处理耗时任务;
- 使用
WorkManager
(推荐),适合延迟或周期性任务,自动适配系统版本; - 避免使用
IntentService
(已过时),可改用Coroutine + Service
。
4. 本地广播(LocalBroadcastManager)的优势是什么?
- 安全性高:仅在当前应用内传播,避免其他应用监听或发送恶意广播,防止数据泄露;
- 效率更高:无需跨进程通信,减少系统资源消耗;
- 生命周期可控:通过
LocalBroadcastManager
管理注册与注销,避免内存泄漏; - 无需权限:因仅在应用内传播,无需声明权限,简化配置。
5. Android 7.0 后对 BroadcastReceiver 有哪些限制?
- 静态注册限制:部分系统广播(如
CONNECTIVITY_CHANGE
、ACTION_NEW_PICTURE
)不再支持静态注册,需改用动态注册; - 隐式广播限制:禁止静态注册的接收器接收隐式广播(未指定包名的广播),除非广播是系统明确允许的(如
BOOT_COMPLETED
); - 后台优化:应用进入后台后,动态注册的接收器可能被系统限制接收广播(需结合
JobScheduler
或WorkManager
)。
解决方式:
- 优先使用动态注册接收系统广播;
- 发送广播时指定包名(显式广播):
intent.setPackage(packageName)
; - 非实时任务改用
WorkManager
。
6. 如何确保广播的安全性(防止恶意接收或发送)?
- 使用本地广播:通过
LocalBroadcastManager
发送,仅应用内可接收; - 权限控制:
- 发送广播时指定权限:
sendBroadcast(intent, "com.example.MY_PERMISSION")
,只有声明该权限的应用可接收; - 接收广播时指定权限:在 Manifest 的
<receiver>
中添加android:permission
,只有拥有该权限的应用发送的广播才能被接收;
- 发送广播时指定权限:
- 显式广播:发送时指定目标组件包名或类名,避免隐式广播被未知应用接收:
-
Intent intent = new Intent("com.example.MY_ACTION"); intent.setPackage("com.example.targetapp"); // 指定目标应用包名 sendBroadcast(intent);
- 限制导出:静态注册的接收器设置
android:exported="false"
,仅允许接收本应用内的广播。
7. 广播接收器的生命周期是怎样的?
- 当广播事件触发时,系统创建
BroadcastReceiver
实例; - 调用
onReceive(Context, Intent)
方法处理事件(此方法必须在 10 秒内完成,否则 ANR); onReceive()
执行完毕后,接收器实例立即被销毁,生命周期结束。
注意:接收器中不能持有组件(如 Activity)的强引用,否则会导致组件无法被回收(内存泄漏)。
8. 粘性广播为什么被废弃?
- 安全性问题:粘性广播会被系统保存,任何应用注册相关接收器都能获取,可能导致敏感数据泄露;
- 内存泄漏风险:系统需持续保存粘性广播数据,增加内存占用;
- 功能替代:可通过
LocalBroadcastManager
(应用内)或SharedPreferences
(保存状态)替代,更安全可控。
9. 如何实现跨进程广播通信?
- 使用系统广播:发送普通广播或有序广播,其他应用通过静态 / 动态注册接收(需处理权限和显式广播);
- 自定义跨进程广播:
- 发送方:通过
sendBroadcast()
发送显式广播(指定目标应用包名); - 接收方:在 Manifest 中静态注册接收器,声明
android:exported="true"
,并指定对应的action
; - 权限控制:通过权限限制只有授权应用才能接收或发送。
- 发送方:通过
示例:应用 A 发送跨进程广播,应用 B 接收
// 应用A发送广播(指定应用B的包名)
Intent intent = new Intent("com.example.CROSS_PROCESS_ACTION");
intent.setPackage("com.example.appb"); // 应用B的包名
sendBroadcast(intent);
// 应用B在Manifest中注册
<receiver
android:name=".CrossProcessReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.example.CROSS_PROCESS_ACTION" />
</intent-filter>
</receiver>
// 应用B的接收器
public class CrossProcessReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("CrossProcess", "收到来自应用A的广播");
}
}
10. BroadcastReceiver 与 EventBus 的区别?
对比维度 | BroadcastReceiver | EventBus(第三方库) |
---|---|---|
适用范围 | 系统级、跨应用、应用内通信 | 仅应用内组件通信(无系统级支持) |
性能 | 跨进程通信时性能较低(需系统调度) | 应用内通信性能更高(内存中直接传递) |
功能丰富度 | 支持有序、粘性等广播类型 | 支持事件优先级、粘性事件、线程切换等 |
配置复杂度 | 需注册 / 注销,静态注册需 Manifest 配置 | 仅需注册 / 注销,代码侵入性低 |
生命周期依赖 | 依赖系统调度,生命周期短暂 | 依赖注册者生命周期,更灵活 |
总结:系统级或跨应用通信用 BroadcastReceiver;应用内组件解耦通信优先用 EventBus(更轻量高效)。
BroadcastReceiver 作为 Android 四大组件之一,是实现事件通知和跨组件通信的重要工具。开发者需掌握其两种注册方式的差异、四类广播的特性及使用限制,尤其注意 Android 7.0 + 后的系统限制和安全性问题。在实际开发中,应根据场景选择合适的广播类型(如应用内通信优先用本地广播),并结合WorkManager
等现代 API 处理后台任务,避免 ANR 和内存泄漏。