Kotlin MVVM中如何合并Room多实体Live/Flow数据生成目标POJO
解决方案:使用MediatorLiveData合并多数据源生成ScreenPOJO
步骤1:在ViewModel中实现数据合并逻辑
在你的ViewModel中添加MediatorLiveData来监听三个数据源的变化,实时合并生成符合要求的ScreenPOJO列表:
class YourViewModel(private val repository: YourRepository) : ViewModel() { // 原有的LiveData定义 val allPersons: LiveData<List<Person>> = repository.allPersons.asLiveData() val allHolidays: LiveData<List<Holiday>> = repository.allHolidays.asLiveData() val allSickness: LiveData<List<Sickness>> = repository.allSickness.asLiveData() // 合并后的LiveData,对外暴露不可变版本 private val _combinedScreenData = MediatorLiveData<List<ScreenPOJO>>() val combinedScreenData: LiveData<List<ScreenPOJO>> = _combinedScreenData init { // 关联三个数据源,任意一个数据变更都会触发合并逻辑 _combinedScreenData.addSource(allPersons) { combineData() } _combinedScreenData.addSource(allHolidays) { combineData() } _combinedScreenData.addSource(allSickness) { combineData() } } /** * 核心合并逻辑:根据人员、假期、病假数据生成ScreenPOJO列表 */ private fun combineData() { // 安全获取各数据源数据,为空时用空列表兜底 val persons = allPersons.value ?: emptyList() val holidays = allHolidays.value ?: emptyList() val sicknesses = allSickness.value ?: emptyList() // 将假期、病假数据转为以personId为键的Map,提升查找效率 val holidayMap = holidays.associateBy { it.personId } val sicknessMap = sicknesses.associateBy { it.personId } // 遍历人员列表,计算每个人员的viewTypeId val screenList = persons.map { person -> val personHoliday = holidayMap[person.id] val personSickness = sicknessMap[person.id] // 无记录时默认状态为false val isOnHoliday = personHoliday?.onHoliday ?: false val isOnSickness = personSickness?.onSickness ?: false // 按照规则生成viewTypeId val viewTypeId = if (!isOnHoliday && !isOnSickness) 1 else 2 ScreenPOJO(viewTypeId, person.name) } // 更新合并后的数据 _combinedScreenData.value = screenList } // 原有的insertPerson方法... }
步骤2:在Activity中观察合并后的数据
在Activity或Fragment中监听combinedScreenData,实时更新UI:
viewModel.combinedScreenData.observe(this) { screenPOJOList -> // 这里处理UI更新逻辑,例如刷新RecyclerView screenPOJOList.forEach { pojo -> Log.d("ScreenData", "姓名:${pojo.personName},类型ID:${pojo.viewTypeId}") } }
特殊场景处理
如果一个人员可能存在多条假期/病假记录(如多次请假),请修改combineData中的状态判断逻辑:
// 检查该人员是否有任意一条假期记录为true val isOnHoliday = holidays.any { it.personId == person.id && it.onHoliday } // 检查该人员是否有任意一条病假记录为true val isOnSickness = sicknesses.any { it.personId == person.id && it.onSickness }
可选:使用Kotlin Flow实现合并(更现代方案)
若Repository返回的是Flow而非LiveData,可使用Flow的combine操作符简化实现:
// ViewModel中定义Flow val combinedScreenFlow: Flow<List<ScreenPOJO>> = combine( repository.allPersons, repository.allHolidays, repository.allSickness ) { persons, holidays, sicknesses -> val holidayMap = holidays.associateBy { it.personId } val sicknessMap = sicknesses.associateBy { it.personId } persons.map { person -> val isOnHoliday = holidayMap[person.id]?.onHoliday ?: false val isOnSickness = sicknessMap[person.id]?.onSickness ?: false val viewTypeId = if (!isOnHoliday && !isOnSickness) 1 else 2 ScreenPOJO(viewTypeId, person.name) } }.flowOn(Dispatchers.IO) // Activity中观察Flow lifecycleScope.launch { viewModel.combinedScreenFlow.collect { screenList -> // 更新UI } }
内容的提问来源于stack exchange,提问作者DevPeter
相关产品推荐
相关产品推荐

