mutableStateOf在MainActivity中不更新?BLE扫描列表无界面响应
核心问题定位
- 状态更新逻辑不符合Jetpack Compose的可观测规则,无法触发UI重组
- 大概率存在ViewModel实例不一致的问题
具体错误分析
1. 状态更新逻辑不被Compose追踪
Jetpack Compose的状态观测机制,仅在给state.value赋值全新的对象实例时,才会触发依赖该状态的UI重组。
你当前的更新逻辑:
val list = lockDeviceList.value // 直接引用原有列表实例 list.add(psLock) lockDeviceList.value = list // 把原实例重新赋值回去,引用地址根本没变化
哪怕你修改了列表里的元素,因为引用地址没变,Compose完全感知不到内容变了,自然不会给任何UI响应。
2. 状态读取时机错配
你在onCreate里启动扫描后立刻打印bluetooth.lockDeviceList.value的时候,扫描还没返回任何数据,拿到的肯定是空列表。后面就算扫描回调拿到了设备,又因为上面的状态更新逻辑不对,UI侧根本收不到变更通知。
修复方案
第一步:换用Compose原生可观察集合
直接把原来的状态声明从mutableStateOf(可变列表)换成mutableStateListOf,这个集合是Compose专门做了变更追踪的,add/remove操作会自动触发UI重组,根本不用手动给value赋值:
// 替换原有声明 val lockDeviceList = mutableStateListOf<PSLock>()
后续在扫描回调里新增设备时,直接操作列表就行:
override fun onDeviceScanned(psLock: PSLock) { if (fakeWhitelist.contains(psLock.name)) { val search = lockDeviceList.find { device -> device.name == psLock.name } if (search == null) { lockDeviceList.add(psLock) // 这个操作会自动触发状态更新 cancelAllScanning() } } }
*如果非要保留原来MutableState<MutableList<PSLock>>的写法,必须保证每次更新都生成全新的列表实例:
// 错误写法 val list = lockDeviceList.value list.add(psLock) lockDeviceList.value = list // 正确写法 lockDeviceList.value = lockDeviceList.value.toMutableList().apply { add(psLock) }
第二步:修正LazyColumn的状态绑定
不要硬取.value,直接把可观察集合传进去,让Compose自动绑定状态依赖:
LazyColumn { // 直接传lockDeviceList本身,不用手动读.value itemsIndexed(items = bluetooth.lockDeviceList) { _, device -> Column(modifier = Modifier.fillMaxWidth()) { Card { Text(device.name) } } } }
第三步:保证ViewModel实例一致
不要在Activity里直接new BluetoothController(),要通过viewModels()委托获取和Activity生命周期绑定的同一实例,不然你在扫描回调里更新的列表,和UI持有的列表根本不是同一个对象,怎么更新都不会有反应:
// Activity里正确的ViewModel获取方式 private val bluetooth: BluetoothController by viewModels()
内容的提问来源于stack exchange,提问作者Chris Pi
相关产品推荐
相关产品推荐

