如何观察多个LiveData的状态,确认两次API请求均加载成功?
实现方案
可以使用Jetpack提供的MediatorLiveData合并两个请求的状态,只需监听这一个合并后的LiveData即可判断是否两个请求都成功。
第一步:修正现有LiveData类型
你当前定义的data1和data2类型声明存在问题,需要调整为包裹DataState的类型:
val data1 = MutableLiveData<DataState<List<Model1>>>() val data2 = MutableLiveData<DataState<List<Model2>>>()
第二步:定义合并状态的LiveData
在ViewModel中新增MediatorLiveData,可以额外定义一个数据类封装两个请求的成功结果:
// 可选:封装两个接口都成功时的返回数据 data class AllDataResult( val data1: List<Model1>, val data2: List<Model2> ) val allDataState = MediatorLiveData<DataState<AllDataResult>>() init { // 把两个请求的LiveData都作为源添加到MediatorLiveData中 allDataState.addSource(data1) { combineStates() } allDataState.addSource(data2) { combineStates() } getData1() getData2() } private fun combineStates() { val state1 = data1.value val state2 = data2.value // 只要有一个还在加载,整体状态为加载中 if (state1 is DataState.Loading || state2 is DataState.Loading) { allDataState.value = DataState.Loading return } // 只要有一个报错,整体状态为报错 if (state1 is DataState.Error) { allDataState.value = DataState.Error(state1.exception) return } if (state2 is DataState.Error) { allDataState.value = DataState.Error(state2.exception) return } // 两个都成功,返回合并后的结果 if (state1 is DataState.Success && state2 is DataState.Success) { allDataState.value = DataState.Success( AllDataResult( data1 = state1.data, data2 = state2.data ) ) } }
第三步:页面层监听逻辑
在Activity/Fragment中只需要监听allDataState这一个LiveData即可:
viewModel.allDataState.observe(this) { state -> when(state) { is DataState.Loading -> { // 展示进度条 progressBar.visibility = View.VISIBLE } is DataState.Error -> { // 隐藏进度条,展示错误提示 progressBar.visibility = View.GONE Toast.makeText(context, state.exception.message, Toast.LENGTH_SHORT).show() } is DataState.Success -> { // 隐藏进度条,渲染两个接口的返回数据 progressBar.visibility = View.GONE renderData1(state.data.data1) renderData2(state.data.data2) } } }
其他可选方案
如果你不需要在ViewModel中保留两个接口的单独状态,也可以直接用async并发请求后合并结果,代码更简洁:
val allDataState = MutableLiveData<DataState<AllDataResult>>() init { getAllData() } private fun getAllData() { viewModelScope.launch { allDataState.postValue(DataState.Loading) try { // 并发请求两个接口 val data1Deferred = async { repository.getData1().data!! } val data2Deferred = async { repository.getData2().data!! } val result = AllDataResult( data1 = data1Deferred.await(), data2 = data2Deferred.await() ) allDataState.postValue(DataState.Success(result)) } catch (e: Exception) { allDataState.postValue(DataState.Error(e)) } } }
这种方式不需要单独维护data1和data2两个LiveData,适合不需要单独使用单个接口返回结果的场景。
内容的提问来源于stack exchange,提问作者farfalletonde
相关产品推荐
相关产品推荐

