- 我有以下设置。**
我有一个带有项目列表的屏幕(PlantsScreen)。当单击列表中的项目时,我将被导航到另一个屏幕(AddEditPlantScreen)。编辑并保存项目并导航回listScreen后,我想显示更新的项目列表。但列表没有显示更新的列表,而是显示编辑项目之前的列表。
为了获得单一的真实来源,我从node. jsBack-End获取数据,然后将其保存到本地存储库(Room)。我认为我需要刷新ViewModel中的状态,以便从我的存储库中获取更新后的列表。
我知道我可以使用一个Job来完成这件事,但是它抛出了一个错误。当返回一个Flow时,这是正确的方法吗?
一个月一个月一个月一个月一个月
- 工厂列表视图模型. kt**
private val _state = mutableStateOf<PlantsState>(PlantsState())
val state: State<PlantsState> = _state
init {
getPlants(true, "")
}
private fun getPlants(fetchFromBackend: Boolean, query: String) {
viewModelScope.launch {
plantRepository.getPlants(fetchFromBackend, query)
.collect { result ->
when (result) {
is Resource.Success -> {
result.data?.let { plants ->
_state.value = state.value.copy(
plants = plants,
)
}
}
}
}
}
}
- 这是我从中获取列表中项目的存储库。**
// plantsRepository.kt
override suspend fun getPlants(
fetchFromBackend: Boolean,
query: String
): Flow<Resource<List<Plant>>> {
return flow {
emit(Resource.Loading(true))
val localPlants = dao.searchPlants(query)
emit(
Resource.Success(
data = localPlants.map { it.toPlant() },
)
)
val isDbEmpty = localPlants.isEmpty() && query.isBlank()
val shouldLoadFromCache = !isDbEmpty && !fetchFromBackend
if (shouldLoadFromCache) {
emit(Resource.Loading(false))
return@flow
}
val response = plantApi.getPlants().plants
dao.clearPlants()
dao.insertPlants(
response.map { it.toPlantEntity() }
)
emit(Resource.Success(
data = dao.searchPlants("").map { it.toPlant() }
))
emit(Resource.Loading(false))
}
}
The full code for reference can be found here:
https://gitlab.com/fiehra/plants
∮谢谢你∮
2条答案
按热度按时间owfi6suc1#
事实上你有两个真相来源:一个是房间数据库,另一个是视图模型中的
_state
对象。为了将其简化为单一的事实来源,您需要将流的集合移动到需要数据的组合函数中。您将使用来自工件
androidx.lifecycle:lifecycle-runtime-compose
的扩展函数StateFlow.collectAsStateWithLifecycle()
来完成此操作。这将在您的组合对象进入和离开组合时自动订阅和取消订阅流。由于您希望业务逻辑保留在视图模型中,因此必须在收集流之前应用它,其思想是仅在视图模型中 * 转换 * 流:
如果您希望
fetchFromBackend
和query
具有其他值,则只需更新变量;流将自动重新计算状态对象。2它可以像调用这样的东西一样简单:从结果创建
PlantsState
的逻辑可以在视图模型中的其他地方完成。将您的PlantsViewModel.getPlants()
替换为以下内容,并将其放置在PlantsViewModel类之外的文件级别:将
PlantsState
类替换为:然后,无论您在何处需要状态(例如在PlantsScreen中),您都可以使用以下命令获取状态对象
多亏了kotlin流,
state
将总是包含房间数据库中最新的数据,多亏了compose魔术,当state
对象中的任何东西更新时,你的可组合对象将总是更新,所以你真的只有一个单一的真实来源。此外:
PlantRepository.getPlants()
不应该被标记为暂停函数,因为它只是创建一个流,不会阻塞;长时间运行的数据检索将在收集器中完成。androidx.compose.runtime.getValue
和androidx.compose.runtime.setValue
,以便某些代理能够工作。cqoc49vn2#
在@Leviathan能够为我指出正确的方向之后,我通过改变存储库函数的返回类型、实现用例和返回
Flow<List<Plant>>
而不是Flow<Resource<List<Plant>>>
来重构代码,以简化操作。进一步删除了Leviathan指出的
PlantDao.kt
和PlantRepository.kt
中函数的挂起标记。我开始在我的视图模型中使用Job和GetPlants用例,如下所示:
我还必须删除
PlantDao.kt
中的挂起这是我的GetPlants用例的代码: