目录
[1. 是什么?](#1. 是什么?)
[2. 核心设计思想:发布-订阅模式](#2. 核心设计思想:发布-订阅模式)
[3. 主要用途](#3. 主要用途)
[1. 标准广播](#1. 标准广播)
[2. 有序广播](#2. 有序广播)
[2.1 在 AndroidManifest.xml 中注册,并设置优先级:](#2.1 在 AndroidManifest.xml 中注册,并设置优先级:)
[2.2 定义三个广播接收器](#2.2 定义三个广播接收器)
[2.3 在 Activity 或 Service 中发送有序广播:](#2.3 在 Activity 或 Service 中发送有序广播:)
[2.4 结果](#2.4 结果)
[四、 广播接收器的注册方式](#四、 广播接收器的注册方式)
[1. 静态注册](#1. 静态注册)
[2. 动态注册](#2. 动态注册)
[五、 本地广播(应用内广播)](#五、 本地广播(应用内广播))
[六、 安全考量](#六、 安全考量)
[七、 最佳实践与注意事项](#七、 最佳实践与注意事项)
我们来对 Android 四大组件之一的 BroadcastReceiver(广播接收器) 进行一次全面而深入的解析。本文将涵盖其定义、工作原理、类型、注册方式、使用方法、安全考量、最佳实践以及进化历程。
一、广播接收器概述
1. 是什么?
BroadcastReceiver(广播接收器)是一个用于响应系统范围或应用内广播消息 的组件。它充当应用程序与系统事件或其他应用程序事件之间的"事件监听器"。
可以把它理解为一种全局的监听器,它不包含用户界面,但在后台工作,当它感兴趣的特定事件(广播)发生时,就会被系统激活并执行相应的代码。
2. 核心设计思想:发布-订阅模式
广播机制完美体现了发布-订阅模式:
-
发布者: 发送一个广播Intent。
-
订阅者: 注册一个 BroadcastReceiver来监听特定类型的广播。
-
系统(作为中介): 当有广播发出时,系统会寻找所有订阅了该广播的接收器,并调用它们的**
onReceive()** 方法。
3. 主要用途
-
监听系统状态变化: 如开机完成、电量低、网络状态改变、屏幕开关、时区变化等。
-
应用内组件通信: 在不同 Activity、Service 等组件之间传递消息,实现解耦。
-
应用间通信: 一个应用可以发送广播,让其他应用(如果它们注册了相应的接收器)收到并处理。
二、广播的工作原理
-
发送广播: 某个组件(如 Activity、Service 或其他 Receiver)使用
Intent对象,通过Context.sendBroadcast()等方法发送广播。 -
系统匹配: Android 系统接收到广播 Intent 后,会根据 Intent 中的信息(如 Action、Category 等)去查找所有已注册 并且与该 Intent 匹配的 BroadcastReceiver。
-
实例化与执行: 系统会实例化匹配的 Receiver(如果它还没运行),并调用其
onReceive(Context context, Intent intent)方法。 -
生命周期: Receiver 对象的生命周期非常短暂,仅在
onReceive()方法执行期间存活。方法执行完毕后,该实例就会被销毁。
重要限制: 在
onReceive()中不能执行异步操作,也不能开启一个长时间运行的后台线程。因为一旦onReceive()返回,进程可能随时被系统杀死。如果需要进行耗时操作,必须使用goAsync()或启动一个JobIntentService/JobScheduler。
三、广播的类型

1. 标准广播
-
特点: 完全异步。发送后,所有匹配的接收器几乎同时收到广播,它们之间没有顺序,也无法中止广播。
-
发送方法:
sendBroadcast(Intent)
2. 有序广播
-
特点: 同步执行。发送后,同一时间只有一个接收器能收到广播。该接收器执行完后,可以将结果传递给下一个接收器 ,也可以完全中止广播,使其不再继续传播。
-
发送方法:
sendOrderedBroadcast(Intent, String) -
优先级: 通过在注册时设置
android:priority属性来决定接收顺序,数值越大优先级越高(范围:-1000 到 1000)。 -
结果传播: 可以使用 **
setResultExtras(Bundle)**存放数据,下一个接收器可以用getResultExtras(true)获取并修改。 -
中止广播:
abortBroadcast()
接下来通过示例来演示有序广播的流程:这里用一个链式处理的场景,如:权限验证 → 数据验证 → 业务处理 → 结果上报等流程。
2.1 在 AndroidManifest.xml 中注册,并设置优先级:
XML
<receiver
android:name=".PermissionCheckReceiver"
android:enabled="true"
android:exported="false">
<intent-filter android:priority="1000"> <!-- 最高优先级 -->
<action android:name="com.example.ORDERED_BROADCAST_ACTION" />
</intent-filter>
</receiver>
<receiver
android:name=".ContentFilterReceiver"
android:enabled="true"
android:exported="false">
<intent-filter android:priority="500"> <!-- 中等优先级 -->
<action android:name="com.example.ORDERED_BROADCAST_ACTION" />
</intent-filter>
</receiver>
<receiver
android:name=".FinalProcessorReceiver"
android:enabled="true"
android:exported="false">
<intent-filter android:priority="100"> <!-- 最低优先级 -->
<action android:name="com.example.ORDERED_BROADCAST_ACTION" />
</intent-filter>
</receiver>
2.2 定义三个广播接收器
java
//------------------------PermissionCheckReceiver---------------------------------
public class PermissionCheckReceiver extends BroadcastReceiver {
private static final String TAG = "PermissionCheck";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "【权限检查】开始执行...");
// 模拟权限检查
boolean hasPermission = checkUserPermission();
if (!hasPermission) {
Log.w(TAG, "【权限检查】权限不足,中止广播!");
abortBroadcast(); // 中止广播,后续接收器不会执行
return;
}
// 添加处理结果
Bundle resultBundle = getResultExtras(true);
resultBundle.putString("permission_status", "PASS");
setResultExtras(resultBundle);
Log.d(TAG, "【权限检查】权限验证通过,继续传递");
}
private boolean checkUserPermission() {
// 模拟权限检查逻辑,这里简单返回true
return true;
}
}
//--------------------------ContentFilterReceiver -----------------------------------
public class ContentFilterReceiver extends BroadcastReceiver {
private static final String TAG = "ContentFilter";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "【内容过滤】开始执行...");
// 获取上一个接收器的处理结果
Bundle previousResult = getResultExtras(false);
String permissionStatus = previousResult != null ?
previousResult.getString("permission_status") : "UNKNOWN";
Log.d(TAG, "【内容过滤】接收到权限状态: " + permissionStatus);
// 模拟内容过滤
String originalMessage = intent.getStringExtra("message");
String filteredMessage = filterContent(originalMessage);
// 更新结果数据
Bundle resultBundle = getResultExtras(true);
resultBundle.putString("filtered_message", filteredMessage);
resultBundle.putString("content_filter_status", "PROCESSED");
setResultExtras(resultBundle);
Log.d(TAG, "【内容过滤】内容过滤完成,继续传递");
}
private String filterContent(String message) {
// 简单的敏感词过滤
if (message == null) return "";
return message.replace("敏感词", "***");
}
}
//------------------------FinalProcessorReceiver ---------------------------------
public class FinalProcessorReceiver extends BroadcastReceiver {
private static final String TAG = "FinalProcessor";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "【最终处理】开始执行...");
// 获取前面所有接收器的处理结果
Bundle finalResult = getResultExtras(false);
String originalMessage = intent.getStringExtra("message");
String filteredMessage = finalResult != null ?
finalResult.getString("filtered_message") : originalMessage;
String permissionStatus = finalResult != null ?
finalResult.getString("permission_status") : "UNKNOWN";
Log.d(TAG, "======= 最终处理结果 =======");
Log.d(TAG, "原始消息: " + originalMessage);
Log.d(TAG, "过滤后消息: " + filteredMessage);
Log.d(TAG, "权限状态: " + permissionStatus);
Log.d(TAG, "【最终处理】消息处理流程完成");
// 可以在这里更新UI或进行其他操作
Toast.makeText(context, "消息处理完成: " + filteredMessage, Toast.LENGTH_SHORT).show();
}
}
2.3 在 Activity 或 Service 中发送有序广播:
java
public class MainActivity extends AppCompatActivity {
private void sendOrderedBroadcastExample() {
Log.d("BroadcastSender", "准备发送有序广播...");
// 创建广播Intent
Intent orderedIntent = new Intent("com.example.ORDERED_BROADCAST_ACTION");
orderedIntent.putExtra("message", "这是一条包含敏感词的重要消息");
// 发送有序广播
// 参数说明:
// 1. Intent
// 2. 权限字符串(可为null)
// 3. 最终接收器(可选)
// 4. Handler(可为null)
// 5. 初始结果码
// 6. 初始数据(可为null)
// 7. 初始Bundle
sendOrderedBroadcast(
orderedIntent,
null, // 权限
new FinalProcessorReceiver(), // 可选的最终接收器
null, // Handler
Activity.RESULT_OK,
null, // initialData
null // initialExtras
);
Log.d("BroadcastSender", "有序广播已发送");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendButton = findViewById(R.id.send_button);
sendButton.setOnClickListener(v -> sendOrderedBroadcastExample());
}
}
详细解释下sendOrderedBroadcast:
java
public abstract void sendOrderedBroadcast(
//要发送的广播Intent,包含action、data、category等信息。
Intent intent,
//接收器必须拥有的权限。只有声明了该权限的接收器才能接收此广播。
//如:String permission = "com.example.MY_PERMISSION";
//String systemPermission = android.Manifest.permission.INTERNET;
String receiverPermission,
//最终接收器。无论广播是否被中止,这个接收器都会最后执行。
//即使前面的接收器调用了 abortBroadcast(),最终接收器仍会执行
BroadcastReceiver resultReceiver,
//指定处理广播的Handler。控制 onReceive() 方法在哪个线程执行。
//如果为 null:在主线程执行
Handler scheduler,
//初始结果码。接收器可以通过 setResultCode(int code) 修改这个值。
int initialCode,
//初始结果数据。接收器可以通过 setResultData(String data) 修改这个值。
String initialData,
//初始附加数据。接收器可以通过 getResultExtras() 和 setResultExtras() 访问和修改。
Bundle initialExtras
)
2.4 结果
java
BroadcastSender: 准备发送有序广播...
BroadcastSender: 有序广播已发送
PermissionCheck: 【权限检查】开始执行...
PermissionCheck: 【权限检查】权限验证通过,继续传递
ContentFilter: 【内容过滤】开始执行...
ContentFilter: 【内容过滤】接收到权限状态: PASS
ContentFilter: 【内容过滤】内容过滤完成,继续传递
FinalProcessor: 【最终处理】开始执行...
FinalProcessor: ======= 最终处理结果 =======
FinalProcessor: 原始消息: 这是一条包含敏感词的重要消息
FinalProcessor: 过滤后消息: 这是一条包含***的重要消息
FinalProcessor: 权限状态: PASS
FinalProcessor: 【最终处理】消息处理流程完成
四、 广播接收器的注册方式
有两种方式将 BroadcastReceiver 注册到系统中,使其开始监听。

1. 静态注册
在 AndroidManifest.xml 文件中进行声明。
XML
<receiver
android:name=".MyBootCompletedReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<!-- 监听系统启动完成广播 -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
-
特点:
-
应用安装后即注册,即使应用未启动,Receiver 也能被激活(系统会先启动你的应用进程)。
-
常用于监听系统事件(如开机启动)。
-
从 Android 8.0 (API 26) 开始,大部分隐式广播不能再使用静态注册 ,以防止应用过度消耗资源。
BOOT_COMPLETED是少数例外之一。
-
2. 动态注册
在代码中(如 Activity 或 Service 中)通过调用 **registerReceiver()**方法进行注册。
java
public class MainActivity extends AppCompatActivity {
private MyNetworkReceiver networkReceiver;
@Override
protected void onResume() {
super.onResume();
// 1. 创建Receiver实例
networkReceiver = new MyNetworkReceiver();
// 2. 创建IntentFilter
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
// 3. 注册Receiver
registerReceiver(networkReceiver, filter);
}
@Override
protected void onPause() {
super.onPause();
// 4. 必须反注册!防止内存泄漏和不必要的系统开销
if (networkReceiver != null) {
unregisterReceiver(networkReceiver);
networkReceiver = null;
}
}
}
特点:
-
注册与组件(如 Activity)生命周期绑定,灵活性强。
-
必须在合适的时机(如
onPause()或onDestroy())调用unregisterReceiver()进行反注册。 -
不受 Android 8.0 隐式广播限制的影响,可以监听任何广播。
五、 本地广播(应用内广播)
为了安全和效率,如果广播只在应用内部使用,强烈推荐使用 LocalBroadcastManager (现已并入 AndroidX)或类似的机制。本地广播无法通过静态注册方式来接受,相比起系统全局广播更加高效
-
优点:
-
安全: 数据不会泄露给其他应用,其他应用也无法向你发送广播。
-
高效: 不需要系统介入,进程内通信,开销小。
-
便捷: 不需要担心 Android 8.0 的静态注册限制。
-
-
使用方法:
java
// 1. 获取LocalBroadcastManager实例
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
// 2. 注册接收器(动态注册方式)
localBroadcastManager.registerReceiver(myLocalReceiver, new IntentFilter("LOCAL_ACTION"));
// 3. 发送广播
Intent localIntent = new Intent("LOCAL_ACTION");
localIntent.putExtra("data", "Local message");
localBroadcastManager.sendBroadcast(localIntent);
// 4. 反注册
localBroadcastManager.unregisterReceiver(myLocalReceiver);
六、 安全考量
广播是跨进程通信的,因此安全性至关重要。
-
权限:
-
在发送时指定权限:
sendBroadcast(Intent, String)。只有拥有该权限的接收器才能收到广播。 -
在注册时指定权限: 在静态注册的
<receiver>标签或动态注册的registerReceiver()方法中指定权限。只有拥有该权限的发送者发出的广播才能被接收。
-
-
android:exported属性:-
在静态注册中,此属性决定该 Receiver 是否能接收来自其他应用的广播。
-
false:仅接收同一应用内或同一用户ID下的组件发出的广播。 -
true:可以接收来自任何应用的广播。 -
最佳实践: 如果 Receiver 不需要接收外部广播,显式设置为
false。
-
-
避免敏感信息: 不要在隐式广播的 Intent 中携带敏感数据,因为任何注册了该广播的应用都能收到。
七、 最佳实践与注意事项
onReceive()中不要做耗时操作: 重申这一点。如果需要,请使用goAsync()获取一个PendingResult对象,然后在后台线程中完成工作并调用finish()。
java
@Override
public void onReceive(Context context, Intent intent) {
final PendingResult pendingResult = goAsync();
AsyncTask<String, Integer, String> asyncTask = new AsyncTask<String, Integer, String>() {
@Override
protected String doInBackground(String... params) {
// 在这里执行耗时操作
return "Done";
}
@Override
protected void onPostExecute(String s) {
// 必须调用finish()
pendingResult.finish();
}
};
asyncTask.execute();
}
-
精确的 IntentFilter: 尽量使用更具体的 Action,避免使用过于宽泛的 Filter,以减少不必要的激活和资源浪费。
-
生命周期管理: 动态注册一定要配对反注册。
-
优先使用 LocalBroadcastManager: 对于应用内通信,它是首选。
推荐替代方案:
JobScheduler/WorkManager: 用于调度后台任务,是执行延迟、异步任务的首选。
Foreground Service+ 通知: 用于需要用户感知的长时间运行任务。
LocalBroadcastManager: 用于应用内通信。第三方事件总线: 如 EventBus、RxJava,用于组件间解耦通信,但它们只在进程内有效。
八、常用的系统广播
最后给大家提供下我们平常可能会用到的一些系统广播:
java
intent.action.AIRPLANE_MODE;
//关闭或打开飞行模式时的广播
Intent.ACTION_BATTERY_CHANGED;
//充电状态,或者电池的电量发生变化
//电池的充电状态、电荷级别改变,不能通过组建声明接收这个广播,只有通过Context.registerReceiver()注册
Intent.ACTION_BATTERY_LOW;
//表示电池电量低
Intent.ACTION_BATTERY_OKAY;
//表示电池电量充足,即从电池电量低变化到饱满时会发出广播
Intent.ACTION_BOOT_COMPLETED;
//在系统启动完成后,这个动作被广播一次(只有一次)。
Intent.ACTION_CAMERA_BUTTON;
//按下照相时的拍照按键(硬件按键)时发出的广播
Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
//当屏幕超时进行锁屏时,当用户按下电源按钮,长按或短按(不管有没跳出话框),进行锁屏时,android系统都会广播此Action消息
Intent.ACTION_CONFIGURATION_CHANGED;
//设备当前设置被改变时发出的广播(包括的改变:界面语言,设备方向,等,请参考Configuration.java)
Intent.ACTION_DATE_CHANGED;
//设备日期发生改变时会发出此广播
Intent.ACTION_DEVICE_STORAGE_LOW;
//设备内存不足时发出的广播,此广播只能由系统使用,其它APP不可用?
Intent.ACTION_DEVICE_STORAGE_OK;
//设备内存从不足到充足时发出的广播,此广播只能由系统使用,其它APP不可用?
Intent.ACTION_DOCK_EVENT;
//
//发出此广播的地方frameworks\base\services\java\com\android\server\DockObserver.java
Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE;
////移动APP完成之后,发出的广播(移动是指:APP2SD)
Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
//正在移动APP时,发出的广播(移动是指:APP2SD)
Intent.ACTION_GTALK_SERVICE_CONNECTED;
//Gtalk已建立连接时发出的广播
Intent.ACTION_GTALK_SERVICE_DISCONNECTED;
//Gtalk已断开连接时发出的广播
Intent.ACTION_HEADSET_PLUG;
//在耳机口上插入耳机时发出的广播
Intent.ACTION_INPUT_METHOD_CHANGED;
//改变输入法时发出的广播
Intent.ACTION_LOCALE_CHANGED;
//设备当前区域设置已更改时发出的广播
Intent.ACTION_MANAGE_PACKAGE_STORAGE;
//
Intent.ACTION_MEDIA_BAD_REMOVAL;
//未正确移除SD卡(正确移除SD卡的方法:设置--SD卡和设备内存--卸载SD卡),但已把SD卡取出来时发出的广播
//广播:扩展介质(扩展卡)已经从 SD 卡插槽拔出,但是挂载点 (mount point) 还没解除 (unmount)
Intent.ACTION_MEDIA_BUTTON;
//按下"Media Button" 按键时发出的广播,假如有"Media Button" 按键的话(硬件按键)
Intent.ACTION_MEDIA_CHECKING;
//插入外部储存装置,比如SD卡时,系统会检验SD卡,此时发出的广播?
Intent.ACTION_MEDIA_EJECT;
//已拔掉外部大容量储存设备发出的广播(比如SD卡,或移动硬盘),不管有没有正确卸载都会发出此广播?
//广播:用户想要移除扩展介质(拔掉扩展卡)。
Intent.ACTION_MEDIA_MOUNTED;
//插入SD卡并且已正确安装(识别)时发出的广播
//广播:扩展介质被插入,而且已经被挂载。
Intent.ACTION_MEDIA_NOFS;
//
Intent.ACTION_MEDIA_REMOVED;
//外部储存设备已被移除,不管有没正确卸载,都会发出此广播?
// 广播:扩展介质被移除。
Intent.ACTION_MEDIA_SCANNER_FINISHED;
//广播:已经扫描完介质的一个目录
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE;
//
Intent.ACTION_MEDIA_SCANNER_STARTED;
//广播:开始扫描介质的一个目录
Intent.ACTION_MEDIA_SHARED;
// 广播:扩展介质的挂载被解除 (unmount),因为它已经作为 USB 大容量存储被共享。
Intent.ACTION_MEDIA_UNMOUNTABLE;
//
Intent.ACTION_MEDIA_UNMOUNTED
// 广播:扩展介质存在,但是还没有被挂载 (mount)。
Intent.ACTION_NEW_OUTGOING_CALL;
Intent.ACTION_PACKAGE_ADDED;
//成功的安装APK之后
//广播:设备上新安装了一个应用程序包。
//一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)
Intent.ACTION_PACKAGE_CHANGED;
//一个已存在的应用程序包已经改变,包括包名
Intent.ACTION_PACKAGE_DATA_CLEARED;
//清除一个应用程序的数据时发出的广播(在设置--应用管理--选中某个应用,之后点清除数据时?)
//用户已经清除一个包的数据,包括包名(清除包程序不能接收到这个广播)
Intent.ACTION_PACKAGE_INSTALL;
//触发一个下载并且完成安装时发出的广播,比如在电子市场里下载应用?
//
Intent.ACTION_PACKAGE_REMOVED;
//成功的删除某个APK之后发出的广播
//一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)
Intent.ACTION_PACKAGE_REPLACED;
//替换一个现有的安装包时发出的广播(不管现在安装的APP比之前的新还是旧,都会发出此广播?)
Intent.ACTION_PACKAGE_RESTARTED;
//用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播)
Intent.ACTION_POWER_CONNECTED;
//插上外部电源时发出的广播
Intent.ACTION_POWER_DISCONNECTED;
//已断开外部电源连接时发出的广播
Intent.ACTION_PROVIDER_CHANGED;
//
Intent.ACTION_REBOOT;
//重启设备时的广播
Intent.ACTION_SCREEN_OFF;
//屏幕被关闭之后的广播
Intent.ACTION_SCREEN_ON;
//屏幕被打开之后的广播
Intent.ACTION_SHUTDOWN;
//关闭系统时发出的广播
Intent.ACTION_TIMEZONE_CHANGED;
//时区发生改变时发出的广播
Intent.ACTION_TIME_CHANGED;
//时间被设置时发出的广播
Intent.ACTION_TIME_TICK;
//广播:当前时间已经变化(正常的时间流逝)。
//当前时间改变,每分钟都发送,不能通过组件声明来接收,只有通过Context.registerReceiver()方法来注册
Intent.ACTION_UID_REMOVED;
//一个用户ID已经从系统中移除发出的广播
//
Intent.ACTION_UMS_CONNECTED;
//设备已进入USB大容量储存状态时发出的广播?
Intent.ACTION_UMS_DISCONNECTED;
//设备已从USB大容量储存状态转为正常状态时发出的广播?
Intent.ACTION_USER_PRESENT;
//
Intent.ACTION_WALLPAPER_CHANGED;
//设备墙纸已改变时发出的广播