Jetpack Compose中Bluetooth ACTION_STATE_CHANGED广播接收器被调用两次问题
解决Jetpack Compose中蓝牙关闭时
BluetoothAdapter.ACTION_STATE_CHANGED广播触发两次的问题 在Jetpack Compose应用中监听蓝牙状态时遇到异常:关闭蓝牙时,BluetoothAdapter.ACTION_STATE_CHANGED广播接收器的onReceive方法会被触发两次,导致状态更新逻辑执行多次,不符合预期。
问题代码
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { var isBluetoothEnable by remember { mutableStateOf(false) } ScreenOne(isBluetoothEnable) { isBluetoothEnable = it } } } } @Composable fun ScreenOne(isBluetoothEnable: Boolean, onBluetoothChange: (Boolean) -> Unit) { Text(text = "Hello world isBluetoothEnable $isBluetoothEnable") BluetoothStateListener { onBluetoothChange(it) Log.i("BluetoothStateListener", "isBluetoothEnable $it") } } @Composable fun BluetoothStateListener( context: Context = LocalContext.current, isBluetoothEnable: (Boolean) -> Unit ) { DisposableEffect(Unit) { val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (intent?.action == BluetoothAdapter.ACTION_STATE_CHANGED) { val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR) isBluetoothEnable(state == BluetoothAdapter.STATE_ON) } } } val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) context.registerReceiver(receiver, filter) onDispose { context.unregisterReceiver(receiver) } } }
日志信息
2024-02-29 22:44:16.938 15425-15425 BluetoothStateListener com.example.simplecomposenavigation I isBluetoothEnable false 2024-02-29 22:44:17.215 15425-15425 BluetoothStateListener com.example.simplecomposenavigation I isBluetoothEnable true
问题根源
Android系统在蓝牙状态变化时会发送多轮广播:
- 开启流程:先推送
STATE_TURNING_ON(正在开启)状态,再推送STATE_ON(已开启)状态 - 关闭流程:先推送
STATE_TURNING_OFF(正在关闭)状态,再推送STATE_OFF(已关闭)状态
原代码仅判断状态是否等于STATE_ON,导致过渡状态(如STATE_TURNING_OFF)也会触发false回调,若系统广播推送时机有波动,就会出现多次回调的情况。另外需确认DisposableEffect的注册逻辑是否稳定,避免因Compose重组导致接收器重复注册。
修复代码
修改广播接收器的状态判断逻辑,只处理最终的STATE_ON和STATE_OFF状态,忽略过渡状态:
@Composable fun BluetoothStateListener( context: Context = LocalContext.current, isBluetoothEnable: (Boolean) -> Unit ) { DisposableEffect(Unit) { val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { intent?.takeIf { it.action == BluetoothAdapter.ACTION_STATE_CHANGED }?.let { val state = it.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR) when(state) { BluetoothAdapter.STATE_ON -> isBluetoothEnable(true) BluetoothAdapter.STATE_OFF -> isBluetoothEnable(false) // 过滤过渡状态,避免无效回调 } } } } val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) context.registerReceiver(receiver, filter) onDispose { context.unregisterReceiver(receiver) } } }
额外排查点
如果修复后仍有多次回调,可检查:
- 是否在多个可组合函数中重复调用了
BluetoothStateListener - 是否因Activity重建(如屏幕旋转)导致接收器重复注册,可在
DisposableEffect的注册/注销逻辑中添加日志,确认执行时机
内容的提问来源于stack exchange,提问作者Compose Learner
相关产品推荐
相关产品推荐

