Каждый раз, когда вы вызываете .observe()
в LiveData, Observer получает последнее значение этой LiveData. В некоторых случаях это может быть полезно, но не в моем.
Каждый раз, когда я вызываю
.observe()
, я хочу, чтобы Observer получал только будущие изменения LiveData, но не то значение, которое он сохраняет при вызове.observe()
.У меня может быть несколько наблюдателей для экземпляра LiveData. Я хочу, чтобы все они получали обновления LiveData, когда они появляются.
Я хочу, чтобы каждое обновление LiveData использовалось каждым наблюдателем только один раз. Я думаю, что это всего лишь переформулировка первого требования, но у меня уже кружится голова, и я не уверен в этом.
При поиске этой проблемы я натолкнулся на два распространенных подхода:
Оберните данные в
LiveData<SingleEvent<Data>>
и проверьте этотSingleEvent
класс, если он уже был использован.Расширьте
MediatorLiveData
и используйте карту поиска, если Наблюдатель уже получил Событие
Примеры этих подходов можно найти здесь: https://gist.github.com/JoseAlcerreca/5b661f1800e1e654f07cc54fe87441af#gistcomment-2783677
К сожалению, ни один из этих примеров не решает всех моих требований. В большинстве случаев проблема заключается в том, что любой новый Observer по-прежнему получает последнее значение LiveData после подписки. Это означает, что уже показанная панель закусок отображается снова и снова, когда пользователь перемещается между экранами.
Чтобы дать вам некоторое представление о том, о чем я говорю / о чем пишу:
Я слежу за дизайном LiveData MVVM для компонентов архитектуры Android:
- 2 ListFragment показывают список записей.
- Они используют 2 экземпляра одного и того же класса ViewModel для наблюдения за LiveData, связанным с пользовательским интерфейсом.
- Пользователь может удалить запись в таком ListFragment. Удаление выполняется ViewModel, вызывающим
Repository.delete()
- ViewModel наблюдает за репозиторием для
RepositoryEvents
.
Поэтому, когда удаление выполнено, репозиторий сообщает об этом ViewModel, а ViewModel сообщает об этом ListFragment.
Теперь, когда пользователь переключается на второй ListFragment, происходит следующее:
- Создается второй фрагмент и вызывает
.observe()
в своей ViewModel. Создается ViewModel и вызывает
.observe()
в репозитории.Репозиторий отправляет текущий
RepositoryEvent
в ViewModel- ViewModel отправляет соответствующее событие пользовательского интерфейса во фрагмент
- Фрагмент показывает Snackbar подтверждения для удаления, которое произошло в другом месте.
Вот упрощенный код:
Фрагмент:
viewModel.dataEvents.observe(viewLifecycleOwner, Observer { showSnackbar() })
viewModel.deleteEntry()
ViewModel:
val dataEvents: LiveData<EntryListEvent> = Transformations.switchMap(repository.events, ::handleRepoEvent)
fun deleteEntry() = repository.deleteEntry()
private fun handleRepoEvent(event: RepositoryEvent): LiveData<EntryListEvent> {
// convert the repository event to an UI event
}
Репозиторий:
private val _events = MutableLiveData<RepositoryEvent>()
val events: LiveData<RepositoryEvent>
get() = _events
fun deleteEntry() {
// delete it from database
_events.postValue(RepositoryEvent.OnDeleteSuccess)
}
LiveData
для состояния просмотра (например, элементы в списке) и для событий (например, показывать панель подтверждения), используя для последнего шаблон одиночного живого события. IMHO, ваш первый критерий (я хочу, чтобы Observer получал только будущие изменения LiveData) не годится - при изменении конфигурации вы не получите текущие данные. - person CommonsWare   schedule 27.04.2019LiveData
или не должен отмечать событие как использованное. Итак, в вашем случае первый наблюдатель должен обрабатывать событие, поэтому второму наблюдателю событие не нужно. - person CommonsWare   schedule 27.04.2019LiveData
. - person CommonsWare   schedule 27.04.2019LiveData
. - person CommonsWare   schedule 27.04.2019