Android [Kotlin] - Вставка нового элемента в выбранный дочерний список в MasterDetail-Flow с использованием общего viewModel - PullRequest
0 голосов
/ 07 марта 2020

Я довольно новичок в android и пытаюсь следовать рекомендуемой архитектуре приложения.

Приложение в основном состоит из двух сущностей, использующих базу данных Room: базу данных и упражнения. Они имеют отношение «многие ко многим», реализованное в соответствии с предложением 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 (просмотр повторного просмотра) и, если щелкнуть тренинг, я хочу показать соответствующие упражнения в отдельном просмотре Detail / Exercise-Recycler. Я сделал это двумя разными фрагментами, и я делюсь данными через 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) }
        })

и отобразить выбранную тренировку со списком упражнений в фрагменте-фрагменте. Во фрагменте детали я также хочу иметь возможность вставлять новые упражнения.

Вот моя проблема:
Когда я добавляю новое упражнение, я использую функцию «insertExerciseToTraining» выше, а затем в репозитории я вставляю упражнение и новый trainingExerciseCrossRef. Но в подробном фрагменте список упражнений не обновляется. Только когда я вернусь к обзору тренировок и снова выберу тренировку. Является ли это даже правильным способом сделать это, используя модель общего представления?
В качестве быстрого исправления я делюсь только идентификатором обучения в viewModel и снова запрашиваю trainingWithExercise из БД, наблюдая и отображая его. Затем при добавлении новых упражнений список обновляется корректно. Но это не лучший способ достижения моей цели или лучший способ использования viewModels.
Есть предложения?

1 Ответ

0 голосов
/ 09 марта 2020

Я нашел обходной путь, но я не уверен, что это лучшая практика. Может быть, есть более чистый путь; но это работает.

Итак, как и прежде, я выбираю тренировку и сохраняю идентификатор выбора в viewModel. Затем я запускаю фрагмент подробностей и наблюдаю полный allTrainingWithExercise-List / LiveData, затем фильтрую этот список для обучения с предыдущим сохраненным идентификатором и устанавливаю его в виде.
Поэтому, когда я обновляю список упражнений обучения добавив новое упражнение, наблюдаемое упражнение allTrainingsWithExercise обновляется, и я «перебираю» тренировку по сохраненному идентификатору тренинга.

dashboardViewModel.allTrainingWithExercises.observe(viewLifecycleOwner, Observer { trainings ->
            trainings?.let { adapter.setTraining(it.filter { it.training.trainingId == dashboardViewModel.selectedTrainingId }[0]) }
        })
...