Как прослушать серию изменений в ViewModel, не пропуская событие?

#android #listener #android-livedata

#Android #прослушиватель #android-livedata

Вопрос:

У меня есть a ViewModel , в котором есть список элементов, которые RecyclerView.Adapter использует a .

Когда пользователь нажимает на один из этих элементов, может произойти одно или несколько из следующих событий:

  • элемент может быть изменен;
  • другие элементы могут быть удалены.

Я использовал LiveData как способ сигнализировать о том, что элемент списка был изменен (более производительный, чем сообщение о том, что весь список был изменен). Но я забывал, что LiveData может пропускать значения.

Пример:

 // on background thread
mutableModificationEvent.postValue(ModificationEvent(...)) // will be skipped
mutableModificationEvent.postValue(ModificationEvent(...))
 

Какой наиболее подходящий способ выполнить эту работу?

Я знаю, что LiveData#setValue() существует. Но поскольку #postValue в какой-то момент значения могут быть пропущены и ошибочно добавлены в код, я отбрасываю LiveData их как вариант.

Комментарии:

1. Я сталкивался с пропуском значений LiveData, но только при получении слишком большого количества обновлений за очень короткий промежуток времени (миллисекунды). Я бы подумал, что это не будет проблемой, если единственные обновления, которые он получает, будут в результате взаимодействия с пользователем?

2. Как насчет того, чтобы объединить их и опубликовать List<ModificationEvent> ? Конечно, для этого потребуется какая-то синхронизация, очистка предыдущего списка, добавление новых элементов в список и в какой-то момент обновление пользовательского интерфейса.

Ответ №1:

Вероятно, вы могли бы использовать один из реактивных потоков, например, в сопрограммах RxJava или Kotlin. Вот пример потока kotlin (взят отсюда):

 val latestNews: Flow<List<ArticleHeadline>> = flow {
    while(true) {
        val latestNews = newsApi.fetchLatestNews()
        emit(latestNews) // Emits the result of the request to the flow
        delay(refreshIntervalMs) // Suspends the coroutine for some time
    }
}
 

Вот пример использования потока с преобразованием его в LiveData (ссылка):

 val user: LiveData<User> = liveData {
  val data = database.loadUser() // loadUser is a suspend function.
  emit(data)
}
 

Я не пробовал это, но похоже, что приведенный выше поток должен выдавать элементы один за другим, и никакие элементы не должны быть пропущены.