17、BroadcastReceiver:静态注册与动态注册、系统广播监听、自定义广播发送
广播,说白了就是 Android 系统里的一种「喊话」机制。你喊一嗓子,谁想听谁听。我刚开始接触这个组件时,觉得它挺简单的——不就是发个消息、收个消息嘛。但实际项目里踩过几次坑之后,才发现这里面的门道还真不少。
今天咱们就把 BroadcastReceiver 彻底聊透。从注册方式到系统广播监听,再到自定义广播的发送,我会把我在实战中积累的经验和教训都抖出来。
广播的两种注册方式
Android 里的广播接收器有两种注册方式:静态注册和动态注册。这两种方式各有各的适用场景,选错了可是会出问题的。
静态注册
静态注册是在 AndroidManifest.xml 里声明 Receiver。应用安装时,系统就会解析这个声明。即使你的应用没在运行,广播来了也能唤醒它。
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
对应的 Receiver 类:
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if ("android.intent.action.BOOT_COMPLETED".equals(action)) {
// 开机完成,启动你的服务或提醒
}
}
}
动态注册
动态注册是在代码里调用 registerReceiver() 方法。这种方式更灵活,但有个前提——你的应用必须在运行中,而且注册的组件必须处于活跃状态。
// 在 Activity 或 Service 中注册
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.BATTERY_CHANGED");
filter.addAction("android.intent.action.TIME_TICK");
registerReceiver(batteryReceiver, filter);
// 别忘了在 onDestroy 或 onPause 中取消注册
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(batteryReceiver);
}
系统广播监听实战
系统广播有很多种,常用的包括:开机完成、网络状态变化、电量变化、屏幕亮灭等。咱们挑几个典型的说说。
| 广播 Action | 触发时机 | 注册方式建议 |
|---|---|---|
| BOOT_COMPLETED | 系统启动完成 | 静态注册 |
| CONNECTIVITY_CHANGE | 网络连接变化 | 动态注册 |
| BATTERY_CHANGED | 电量或充电状态变化 | 动态注册 |
| SCREEN_ON / SCREEN_OFF | 屏幕亮起/熄灭 | 动态注册 |
| TIME_TICK | 每分钟变化 | 动态注册 |
监听网络状态变化是个很常见的需求。我做过一个视频播放器,需要根据网络类型切换清晰度。代码大概是这样的:
private BroadcastReceiver networkReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (activeNetwork != null && activeNetwork.isConnected()) {
int type = activeNetwork.getType();
if (type == ConnectivityManager.TYPE_WIFI) {
// WiFi 环境,可以加载高清
} else {
// 移动网络,降低清晰度
}
} else {
// 网络断开,暂停播放
}
}
};
自定义广播发送
除了监听系统广播,我们也可以自己发广播。这在组件间通信、跨进程通信时特别有用。
发送普通广播
Intent intent = new Intent("com.example.MY_CUSTOM_ACTION");
intent.putExtra("key", "value");
sendBroadcast(intent);
发送有序广播
有序广播可以按优先级依次传递,而且每个接收者可以截断广播或修改数据。
Intent intent = new Intent("com.example.ORDERED_ACTION");
sendOrderedBroadcast(intent, null);
接收者可以在 onReceive 中调用 abortBroadcast() 来截断广播,或者用 setResultExtras() 传递数据给下一个接收者。
知识体系总览
下面这张图把 BroadcastReceiver 的核心知识点串起来了。你可以把它当作一个快速参考。
一些实战建议
说了这么多,最后再分享几点我个人的经验:
- 别在 onReceive 里做耗时操作——这个方法的执行时间只有 10 秒左右,超了会 ANR。我见过有人直接在广播里做网络请求,结果应用卡死。
- LocalBroadcastManager 了解一下——如果你的广播只在应用内部传递,用 LocalBroadcastManager 更安全、更高效。它不会跨进程,也不会有安全风险。
- Android 8.0 之后的限制要牢记——大部分隐式广播已经不能静态注册了。如果你的目标版本比较高,建议优先考虑动态注册或者 JobScheduler。
- 有序广播的优先级别乱设——我曾经把某个接收者的优先级设得特别高,结果它截断了广播,后面的接收者全收不到。调试了半天才发现问题。
广播这个机制,说简单也简单,说复杂也复杂。关键是要理解它的设计初衷——轻量、异步、解耦。用好了,它能让你的应用架构更清晰;用不好,反而会引入一堆奇怪的问题。
嗯,今天就聊到这儿。希望这些内容对你有帮助。