Android中ViewModel LiveData Emit异常,如何复用LiveDataScope实现下拉刷新?
解决方案
要实现下拉刷新并复用原有数据获取逻辑,核心是让LiveData能够重新触发数据请求。可以通过触发器LiveData+switchMap的方式改造ViewModel,同时在Fragment中关联下拉刷新事件。
1. 改造ViewModel代码
把原有数据获取逻辑抽离,通过一个可触发的refreshTrigger来控制LiveData重新执行请求:
class DistanceViewModel(private val distanceRepository: DistanceRepository) : ViewModel() { private val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable -> // 处理异常,比如打印日志或通知UI throwable.printStackTrace() } // 刷新触发器:发送Unit事件即可触发重新请求 private val refreshTrigger = MutableLiveData<Unit>() // 通过switchMap绑定触发器,每次触发都重新创建LiveData执行请求 val distanceLiveData: LiveData<List<Distance>> = refreshTrigger.switchMap { liveData(coroutineExceptionHandler) { val distanceList = distanceRepository.getDistanceList() emit(distanceList) } } init { // 初始加载数据 triggerRefresh() } // 对外暴露的刷新方法,供Fragment调用 fun triggerRefresh() { refreshTrigger.value = Unit // 若需避免主线程阻塞,也可使用refreshTrigger.postValue(Unit) } }
2. 修改Fragment代码
在下拉刷新监听中调用ViewModel的刷新方法,并在数据更新后关闭刷新状态:
// 初始化仅需设置一次Adapter,无需每次数据更新重复设置 binding.recyclerViewDistance.adapter = adapter // 观察LiveData接收数据更新 distanceViewModel.distanceLiveData.observe(viewLifecycleOwner) { distanceList -> distanceList?.let { adapter.submitList(it) // 数据更新完成后关闭下拉刷新动画 binding.swipeRefreshLayoutDistance.isRefreshing = false } } // 设置下拉刷新监听 binding.swipeRefreshLayoutDistance.setOnRefreshListener { // 触发ViewModel重新请求数据 distanceViewModel.triggerRefresh() }
关键说明
switchMap会监听refreshTrigger的变化,每次refreshTrigger发送新值,就会重新执行liveData构建器内的代码,实现数据重新请求,完全复用原有数据获取逻辑。- 异常处理沿用你原有的
coroutineExceptionHandler,保证异常捕获逻辑一致。 - 修正了你Fragment代码的冗余问题:原代码重复调用
adapter.submitList(it)且每次都设置recyclerView.adapter,初始化时设置一次Adapter即可,数据更新仅需调用submitList。
内容的提问来源于stack exchange,提问作者Nima Khalili
相关产品推荐
相关产品推荐

