android - Android [Kotlin] - 使用共享视图模型将新项目插入到 MasterDetail-Flow 上的选定子列表中
问题描述
我对 android 很陌生,我正在尝试遵循推荐的应用程序架构。
该应用程序基本上由两个使用房间数据库的实体组成:培训和练习。它们具有多对多关系,按照 android 开发人员指南中的建议实现,带有一个额外的参考实体和一个 POJO:
@Entity(
tableName = "training_exercise_ref",
primaryKeys = ["trainingId", "exerciseId"])
data class TrainingExerciseCrossRef (
var trainingId: Long,
var exerciseId: Long
)
data class TrainingWithExercise (
@Embedded val training: Training,
@Nullable
@Relation(
parentColumn = "trainingId",
entityColumn = "exerciseId",
associateBy = Junction(TrainingExerciseCrossRef::class)
)
val exercises: List<Exercise>?
默认情况下,培训不需要练习。
现在我想在第一个 Master-View (recyclerview) 中列出所有培训,如果单击培训,我想在单独的 Detail/Exercise-Recyclerview 中显示相应的练习。我通过两个不同的片段来做到这一点,并且我通过开发人员指南中建议的 ViewModel 共享数据:
class DashboardViewModel(application: Application) : AndroidViewModel(application) {
private val trainingRepository: TrainingRepository
val allTrainingWithExercises: LiveData<List<TrainingWithExercise>>
val selectedTraining = MutableLiveData<TrainingWithExercise>()
init {
val trainingDao = TrainingRoomDatabase.getDatabase(application, viewModelScope).trainingDao()
trainingRepository = TrainingRepository(trainingDao)
allTrainingWithExercises = trainingRepository.allTrainingWithExerciseEntries
}
fun selectTraining(trainingWithExercise: TrainingWithExercise) {
selectedTraining.value = trainingWithExercise
}
fun insertExerciseToTraining(trainingId: Long, exercise: Exercise) = viewModelScope.launch {
val newExerciseId: Long = exerciseRepository.insert(exercise)
trainingRepository.insertExerciseOfTraining(trainingId, newExerciseId)
}
因此,当我单击培训时,我将选择保存在 viewModel 中,尝试在片段中设置观察者
dashboardViewModel.selectedTraining.observe(viewLifecycleOwner, Observer { exercises ->
exercises?.let { adapter.setTraining(it) }
})
并在 detail-fragment 中显示所选训练和练习列表。在细节片段中,我还希望能够插入新的练习。
我的问题来了:
当我添加一个新练习时,我使用上面的“insertExerciseToTraining”函数,然后在存储库中,我插入练习和一个新的 trainingExerciseCrossRef。但是在细节片段中,练习列表没有得到更新。只有当我回到培训概览并再次选择培训时。这甚至是使用共享视图模型的正确方法吗?
作为快速修复,我只在 viewModel 中共享训练 id,并再次从数据库中查询 trainingWithExercise,观察并显示它。然后,在插入新练习时,列表会正确更新。但这似乎不是实现我的目标的最佳方式,也不是使用 viewModel 的最佳方式。
有什么建议么?
解决方案
我想出了一个解决方法,但我不确定这是否是最佳做法。也许有更清洁的方法;但它的工作。
所以基本上,如上所述,我正在选择训练,并将选择的 id 保存到 viewModel 中。然后我启动详细信息片段,并观察完整的 allTrainingWithExercise-List/LiveData,然后使用先前保存的 id 过滤此列表以进行训练并将其设置在视图中。
因此,当我通过插入新练习来更新训练的练习列表时,观察到的 allTrainingsWithExercise 会更新,并且我正在通过保存的训练 ID“重新选择”训练。
dashboardViewModel.allTrainingWithExercises.observe(viewLifecycleOwner, Observer { trainings ->
trainings?.let { adapter.setTraining(it.filter { it.training.trainingId == dashboardViewModel.selectedTrainingId }[0]) }
})
推荐阅读
- android - 选项菜单项中的自定义布局显示为空布局
- vba - Outlook将附件保存到文件不起作用
- sql - 日期计算,可能使用分区/行函数
- scala - 火花样本太慢
- regex - 重命名正则表达式中的 Bash 变量
- android - Android在深度睡眠模式下失败改造http调用
- python - 将 CSV 导入 pyspark 数据框
- android - 使用 PlaceFilter() 和 Google Places API 按类型过滤地点
- xml - 如何从多个节点值中选择 Powershell 中的特定 XML 节点?
- javascript - 无法提取 ResultSet org.hibernate.exception.SQLGrammarException