广播接收器 → Flow + Lifecycle

2 阅读1分钟

广播接收器 → Flow + Lifecycle

老写法(Java + BroadcastReceiver)

private BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
        tvBattery.setText("电量:" + level + "%");
    }
};

@Override
protected void onResume() {
    super.onResume();
    IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    registerReceiver(batteryReceiver, filter);
}

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(batteryReceiver);
}

问题在哪里

register/unregister 必须在正确的生命周期成对调用,时机一错就崩。每个广播接收器都要写注册逻辑和解注册逻辑,多个广播到处都是散落的 IntentFilter。

新写法(Flow + Lifecycle)

// 封装为 Flow
fun batteryLevelFlow(context: Context): Flow<Int> = callbackFlow {
    val receiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
            trySend(level)
        }
    }
    context.registerReceiver(receiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
    awaitClose { context.unregisterReceiver(receiver) }
}

// 使用 — 自动绑定生命周期
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        batteryLevelFlow(this@MainActivity).collect { level ->
            tvBattery.text = "电量:$level%"
        }
    }
}

一句话注意

callbackFlow 内部 registerReceiverawaitCloseunregisterReceiver,生命周期完全自动绑定,不需要手动 register/unregister。repeatOnLifecycle(STARTED) 确保前台才收集、后台自动取消,和 onResume/onPause 的注册时机语义一致。

Intent.ACTION_BATTERY_CHANGED 这种粘性广播不能用 context.registerReceiver 注册结果返回 null 的问题——因为它是粘性广播,即使是首次注册也会立刻收到回调,没有问题。但注意这个广播不能通过 manifest 静态注册,只能动态注册。


Java Android 老项目迁移系列,持续更新中。