当 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)
}