Android 广播机制入门:动态注册与生命周期避坑
## Android 广播机制:动态注册与生命周期先看现象
Android 广播机制:动态注册与生命周期最常见的问题,不是广播收不到,而是页面已经销毁、Receiver 还活着,或者同一组件重复注册,最后把一次系统事件放大成多次回调。现场如果只看 logcat,很容易误以为是 ROM 兼容性问题,实际更常见的是注册时机、注销时机和 Context 作用域没收紧。
## Android 广播机制先这样修
先把 Receiver 的 owner 钉死:到底归 Activity、Fragment 还是 Application;再把注册/反注册时机与生命周期对齐;最后补一层事件去重与调试日志。这个顺序的价值在于不用大改业务逻辑,就能先把“重复回调”“页面退出后仍触发”“横竖屏切换后异常”这几类高频坑压下去。
## Android 广播机制示例代码
1. 动态注册示例
class NetworkReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("NetworkReceiver", "action=${intent.action}")
}
}
class DemoActivity : AppCompatActivity() {
private val receiver = NetworkReceiver()
override fun onStart() {
super.onStart()
registerReceiver(receiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
}
override fun onStop() {
unregisterReceiver(receiver)
super.onStop()
}
}
2. 调试命令
adb shell dumpsys activity broadcasts
adb logcat -d | grep -i "BroadcastReceiver|ReceiverCallNotAllowedException"
3. 去重辅助代码
class ReceiverGate {
private var lastAction: String? = null
fun shouldHandle(action: String): Boolean {
if (lastAction == action) return false
lastAction = action
return true
}
}
## Android 广播机制常见坑
先盯三类:一是注册在 onCreate、却直到 onDestroy 才注销,导致前后台切换期间事件污染;二是 Fragment 用错宿主 Context,页面重建后旧 Receiver 还在;三是一个事件源被多个 Receiver 重复消费,最终把排查线索搅乱。很多团队不是不会写 Receiver,而是没把生命周期边界写清楚。
## 报错怎么处理
1. 收不到广播
先确认是系统版本限制、导出配置问题,还是根本没注册成功。Android 8 之后很多隐式广播就不能再按老写法指望系统派发,先看 action,再看注册方式。
adb shell dumpsys package your.package.name | grep -i receiver -n
adb shell dumpsys activity broadcasts
2. 重复触发
如果一次网络切换触发了多次 UI 更新,先查是不是多次 registerReceiver,再查页面重建后旧实例是否还在。不要一开始就怀疑厂商 ROM,先把本地注册链路打平。
fun safeUnregister(context: Context, receiver: BroadcastReceiver) {
runCatching { context.unregisterReceiver(receiver) }
}
## 命令和代码直接跑
这类主题最适合做成最小模板:一个 Receiver、一个页面、两条命令,先把注册和生命周期跑通,再往业务里嫁接。只要能稳定复现“注册一次、触发一次、退出后不再触发”,这篇内容就和消息队列那篇彻底拉开了骨架。
1. 状态对象
data class BroadcastState(
val action: String,
val registered: Boolean,
val owner: String
)
2. 演示入口
fun printBroadcastState() {
println(BroadcastState("android.net.conn.CONNECTIVITY_CHANGE", true, "DemoActivity"))
}
3. 验证命令
adb shell dumpsys activity broadcasts
adb logcat -d | grep -i "BroadcastReceiver"
