当 RoomDao 中的数据发生变化时,为什么我的流程不触发
Why my flow doesn't triggers, when data changes in RoomDao
我将 RoomDao 与 kotlin 协程和 Flow 结合使用。我想要做的是收集一次训练及其所有练习以及每次练习的所有重复。练习和重复是流程,因为这个值可以改变,我想观察它们。
问题是当我更新练习时,getTrainingExerciseLinksBy
没有触发,我不知道为什么。这是我在用例中的代码:
suspend fun getTrainingWithExercisesAndRepetitionsBy(trainingId: Long): Flow<UiTrainingWithExercisesAndRepetitions> {
/// This method returns Flow<List<TrainingExerciseLink>>
return trainingExerciseLinksRepository.getTrainingExerciseLinksBy(trainingId).flatMapConcat { trainingExerciseLinks ->
trainingExerciseLinks.map { trainingExerciseLink ->
/// This method returns Flow<List<ExerciseRepetition>>
repetitionsRepository.getExerciseRepetitionsBy(trainingExerciseLink.id).map { repetitions ->
/// do some other selects for collecting data about exercise in one training
}.flowOn(Dispatchers.IO)
}.zipFlows()
}.flowOn(Dispatchers.IO)
}
在我的 ViewModel 中,我观察这个方法是这样的:
viewModelScope.launch {
useCase.getTrainingWithExercisesAndRepetitionsBy(trainingId)
.distinctUntilChanged()
.collect {
_exercisesListLiveData.value = it.exercises
_trainingListLiveData.value = it.trainingData
}
}
这段代码有什么问题?
更新:
在我的 DAO 中,我使用 Flows 订阅数据库的更新,如下所示:
@Dao
abstract class TrainingExerciseLinkDao {
@Query("select * from TrainingExerciseLink where trainingId = :trainingId")
abstract fun getTrainingExerciseLinksBy(trainingId: Long): Flow<List<TrainingExerciseLink>>
}
和 ExerciseRepetitionsDao:
@Dao
abstract class ExerciseRepetitionDao {
@Query("select * from ExerciseRepetitionEntity where trainingExerciseId = :trainingExerciseId")
abstract fun getExerciseRepetitionsBy(trainingExerciseId: Long): Flow<List<ExerciseRepetitionEntity>>
}
你用错了,因为数据库更新时你的 getTrainingWithExercisesAndRepetitionsBy
不知道,
要解决此问题,请在您的 dao 中使用流程,例如 this example as Room supports Flow
then
viewModelScope.launch {
viewModel.yourFunctionThatGetsDataFromRepository(trainingId)
.distinctUntilChanged()
.collect {
_exercisesListLiveData.value = it.exercises
_trainingListLiveData.value = it.trainingData
}
}
如果更多可以参考this example
实际上我找到了答案,所以也许有人会跳进同样的空白,这个帖子会有所帮助。
我的代码中的问题是我使用了 flatMapConcat。此运算符一次等待从原始 Flow 和 flatMapped Flow 发出,因此在这种情况下它将触发回调。要解决此问题,应使用 flatMapLatest。您可以阅读有关此运算符 .
之间差异的更多信息
所以我的代码现在看起来像这样:
suspend fun getTrainingWithExercisesAndRepetitionsBy(trainingId: Long): Flow<UiTrainingWithExercisesAndRepetitions> {
/// This method returns Flow<List<TrainingExerciseLink>>
/// Here is main change: flatMapConcat -> flatMapLatest
return trainingExerciseLinksRepository.getTrainingExerciseLinksBy(trainingId).flatMapLatest { trainingExerciseLinks ->
trainingExerciseLinks.map { trainingExerciseLink ->
/// This method returns Flow<List<ExerciseRepetition>>
repetitionsRepository.getExerciseRepetitionsBy(trainingExerciseLink.id).map { repetitions ->
/// do some other selects for collecting data about exercise in one training
}.flowOn(Dispatchers.IO)
}.zipFlows()
}.flowOn(Dispatchers.IO)
}
我将 RoomDao 与 kotlin 协程和 Flow 结合使用。我想要做的是收集一次训练及其所有练习以及每次练习的所有重复。练习和重复是流程,因为这个值可以改变,我想观察它们。
问题是当我更新练习时,getTrainingExerciseLinksBy
没有触发,我不知道为什么。这是我在用例中的代码:
suspend fun getTrainingWithExercisesAndRepetitionsBy(trainingId: Long): Flow<UiTrainingWithExercisesAndRepetitions> {
/// This method returns Flow<List<TrainingExerciseLink>>
return trainingExerciseLinksRepository.getTrainingExerciseLinksBy(trainingId).flatMapConcat { trainingExerciseLinks ->
trainingExerciseLinks.map { trainingExerciseLink ->
/// This method returns Flow<List<ExerciseRepetition>>
repetitionsRepository.getExerciseRepetitionsBy(trainingExerciseLink.id).map { repetitions ->
/// do some other selects for collecting data about exercise in one training
}.flowOn(Dispatchers.IO)
}.zipFlows()
}.flowOn(Dispatchers.IO)
}
在我的 ViewModel 中,我观察这个方法是这样的:
viewModelScope.launch {
useCase.getTrainingWithExercisesAndRepetitionsBy(trainingId)
.distinctUntilChanged()
.collect {
_exercisesListLiveData.value = it.exercises
_trainingListLiveData.value = it.trainingData
}
}
这段代码有什么问题?
更新: 在我的 DAO 中,我使用 Flows 订阅数据库的更新,如下所示:
@Dao
abstract class TrainingExerciseLinkDao {
@Query("select * from TrainingExerciseLink where trainingId = :trainingId")
abstract fun getTrainingExerciseLinksBy(trainingId: Long): Flow<List<TrainingExerciseLink>>
}
和 ExerciseRepetitionsDao:
@Dao
abstract class ExerciseRepetitionDao {
@Query("select * from ExerciseRepetitionEntity where trainingExerciseId = :trainingExerciseId")
abstract fun getExerciseRepetitionsBy(trainingExerciseId: Long): Flow<List<ExerciseRepetitionEntity>>
}
你用错了,因为数据库更新时你的 getTrainingWithExercisesAndRepetitionsBy
不知道,
要解决此问题,请在您的 dao 中使用流程,例如 this example as Room supports Flow
then
viewModelScope.launch {
viewModel.yourFunctionThatGetsDataFromRepository(trainingId)
.distinctUntilChanged()
.collect {
_exercisesListLiveData.value = it.exercises
_trainingListLiveData.value = it.trainingData
}
}
如果更多可以参考this example
实际上我找到了答案,所以也许有人会跳进同样的空白,这个帖子会有所帮助。
我的代码中的问题是我使用了 flatMapConcat。此运算符一次等待从原始 Flow 和 flatMapped Flow 发出,因此在这种情况下它将触发回调。要解决此问题,应使用 flatMapLatest。您可以阅读有关此运算符
所以我的代码现在看起来像这样:
suspend fun getTrainingWithExercisesAndRepetitionsBy(trainingId: Long): Flow<UiTrainingWithExercisesAndRepetitions> {
/// This method returns Flow<List<TrainingExerciseLink>>
/// Here is main change: flatMapConcat -> flatMapLatest
return trainingExerciseLinksRepository.getTrainingExerciseLinksBy(trainingId).flatMapLatest { trainingExerciseLinks ->
trainingExerciseLinks.map { trainingExerciseLink ->
/// This method returns Flow<List<ExerciseRepetition>>
repetitionsRepository.getExerciseRepetitionsBy(trainingExerciseLink.id).map { repetitions ->
/// do some other selects for collecting data about exercise in one training
}.flowOn(Dispatchers.IO)
}.zipFlows()
}.flowOn(Dispatchers.IO)
}