如何在Room与Compose中监听可观察查询的排序变化?
问题原因
你当前的实现里,ViewModel中的entities是普通var变量。调用changeSorting更新排序模式并重新赋值entities时,Composable通过collectAsStateWithLifecycle订阅的是最初的Flow实例,不会自动切换到新的Flow,因此无法感知排序后的新数据,也就不会触发LazyColumn重组。
解决方案
将entities改为由排序状态驱动的StateFlow,利用flatMapLatest在排序模式变化时自动切换数据库查询,并将结果转为可订阅的StateFlow。
修改ViewModel代码
class EntityViewModel(application: Application) : AndroidViewModel(application) { private val entityDao = AppDatabase.getDatabase(context = application.baseContext).entityDao() private val _selectedSortMode = MutableStateFlow(EntitySortMode.NEWEST) val selectedSortMode = _selectedSortMode.asStateFlow() // 监听排序模式变化,自动切换查询并转为StateFlow val entities: StateFlow<List<Entity>> = selectedSortMode .flatMapLatest { sortMode -> // 排序模式变更时,发起新的数据库查询 entityDao.all(sortMode.string) } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), // 订阅者消失后保留5秒缓存 initialValue = emptyList() ) fun changeSorting(newSortMode: EntitySortMode) { _selectedSortMode.value = newSortMode // 无需手动调用updateDatabaseQuery,flatMapLatest会自动处理 } }
修改Composable代码
@Composable fun EntityView(viewModel: EntityViewModel) { // 直接收集ViewModel中的StateFlow,初始值已在ViewModel定义 val entities by viewModel.entities.collectAsStateWithLifecycle() LazyColumn { items( entities, key = { it.primaryKey } ) { entity -> Box( modifier = Modifier .animateItem() .clickable {} ) { RowItem(entity) } } } }
原理说明
flatMapLatest会在selectedSortMode变化时,取消之前的数据库Flow订阅,立即订阅新的查询Flow,保证始终获取最新排序的数据。stateIn将普通Flow转换为StateFlow,指定初始值和订阅策略,让Composable能稳定收集数据并触发重组。
内容的提问来源于stack exchange,提问作者stackunderflow
相关产品推荐
相关产品推荐

