如何合并LiveData?UDF架构下State类更新UI失败排查
排查MediatorLiveData映射界面状态失败的问题
你的代码里有几个关键错误导致_categories无法正确接收数据更新,下面逐一拆解并给出修复方案:
核心错误点
1. MediatorLiveData是局部对象,未被持有
你在getCategories的协程里创建了MediatorLiveData,但它只是个临时变量,代码执行完这个代码块后就会被垃圾回收,根本没法持续监听result(也就是getListCategoryUseCase()返回的LiveData)的变化。而且**getListCategoryUseCase()返回的是LiveData,不需要在协程里调用**——LiveData本身就是异步数据流,协程在这里完全多余。
2. 错误的异常捕获逻辑
getListCategoryUseCase()返回LiveData,调用它不会抛出IOException,所以你的catch块永远不会触发。LiveData的数据流异常应该在观察者中处理,而不是直接调用方法时捕获。
3. 状态更新未重置loading状态
初始设置loading = true后,后续拿到数据时没有把loading设为false,会导致进度条一直显示,界面状态异常。
修复后的ViewModel代码
class MenuViewModel @Inject constructor( private val loadCategoryUseCase: LoadCategoryUseCase, private val getListCategoryUseCase: GetListCategoryUseCase ) : ViewModel() { private val _categories = MutableLiveData<StateMenuFragment>() val categories: LiveData<StateMenuFragment> get() = _categories val categoryTest = getListCategoryUseCase() // 测试变量 // 把MediatorLiveData声明为成员变量,确保持有引用 private val categoryMediator = MediatorLiveData<List<Category>>() init { viewModelScope.launch { loadCategoryUseCase() } getCategories() } private fun getCategories() { // 初始状态:显示加载中 _categories.value = StateMenuFragment(loading = true) // 监听getListCategoryUseCase返回的LiveData categoryMediator.addSource(getListCategoryUseCase()) { categoryList -> // 更新状态:关闭加载,填充数据 val updatedState = _categories.value?.copy( loading = false, result = categoryList ) ?: StateMenuFragment( loading = false, result = categoryList ) _categories.value = updatedState } } // 可选:如果需要处理LiveData的异常,可以在观察者中处理,或者在UseCase层封装错误状态 }
优化后的Fragment代码
去掉重复的订阅逻辑,只保留对categories的监听即可:
class MenuFragment : Fragment() { private fun updateState() { viewModel.categories.observe(viewLifecycleOwner) { state -> // 先默认隐藏进度条,再根据状态调整 binding.progressBar.visibility = View.GONE if (state.loading) { binding.progressBar.visibility = View.VISIBLE } if (state.error.isError) { Toast.makeText(requireContext(), state.error.errorMessage, Toast.LENGTH_SHORT).apply { setGravity(Gravity.CENTER, 0, 0) }.show() } menuAdapter.submitList(state.result) } } }
额外建议
- 把
StateMenuFragment里的result改成val,符合单向数据流的不可变原则,避免意外修改状态。 - 如果需要处理数据加载失败的情况,建议在
GetListCategoryUseCase中返回包含错误状态的密封类,或者直接在LiveData中传递错误信息,而不是靠捕获异常(因为Room查询不会抛出IOException,除非是数据库操作的底层错误)。
内容的提问来源于stack exchange,提问作者Vladislav Rubashkin
相关产品推荐
相关产品推荐

