如何基于首个返回值条件组合LiveData/Flow,封装带泛型数据的Status状态
实现思路
你可以通过Jetpack提供的MediatorLiveData实现两个LiveData的条件组合,核心逻辑是:
- 缓存两个LiveData的最新发射值
- 状态流发射非成功状态时直接透传对应状态
- 仅当状态流为
Success时,才把最新的业务数据包装成Status.Success<T>向下发射
具体实现代码
第一步:引入依赖(如未引入)
在模块build.gradle中添加LiveData KTX依赖:
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
第二步:编写通用组合扩展函数
import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.LiveData fun <T> combineStatusWithData( statusLiveData: LiveData<Status<Unit>>, dataLiveData: LiveData<T> ): LiveData<Status<T>> = MediatorLiveData<Status<T>>().apply { // 缓存两个流的最新值 var latestStatus: Status<Unit>? = null var latestData: T? = null // 监听状态流更新 addSource(statusLiveData) { status -> latestStatus = status refreshCombinedValue() } // 监听业务数据流更新 addSource(dataLiveData) { data -> latestData = data refreshCombinedValue() } // 统一处理组合逻辑 fun refreshCombinedValue() { when (val currentStatus = latestStatus) { is Status.Loading -> value = Status.loading(currentStatus.message) is Status.Failure -> value = Status.failed(currentStatus.message) is Status.Success -> { latestData?.let { data -> value = Status.success(data) } // 若存在成功状态先触发、数据还未返回的间隙,可打开下方注释避免空白状态 // ?: run { value = Status.loading("正在加载数据") } } null -> { /* 状态未初始化,不发射事件 */ } } } }
第三步:在ViewModel中调用
class MyViewModel(private val workerContract: IWorkerContract<*, T>) : ViewModel() { val myCombinedState: LiveData<Status<T>> = combineStatusWithData( statusLiveData = workerContract.workInfo, dataLiveData = workerContract.appDatabaseData ) }
可选Flow实现方案
如果你的项目已经适配Kotlin Flow,实现逻辑更简洁:
import androidx.lifecycle.asFlow import androidx.lifecycle.asLiveData import kotlinx.coroutines.flow.combine class MyViewModel(private val workerContract: IWorkerContract<*, T>) : ViewModel() { val myCombinedState = combine( workerContract.workInfo.asFlow(), workerContract.appDatabaseData.asFlow() ) { status, data -> when (status) { is Status.Loading -> Status.loading<T>(status.message) is Status.Failure -> Status.failed<T>(status.message) is Status.Success -> Status.success(data) } }.asLiveData() }
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

