Как решить проблему отправки одному наблюдателю с помощью LiveEvent

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

Чтобы понять LiveData, нам сначала нужно понять шаблон наблюдателя. Это шаблон разработки программного обеспечения, в котором объект (называемый субъектом) поддерживает список своих зависимых элементов (называемых наблюдателями) и автоматически уведомляет их о любых изменениях состояния, обычно вызывая один из их методов.

Если вы не знаете о LiveData или о том, как она работает, просмотрите этот фрагмент, прежде чем продолжить для лучшего понимания.

Вариант использования

Обычно наблюдение за LiveData используется для отображения закусочной или для выполнения некоторых настраиваемых действий, таких как отображение диалогового окна, навигации и т. Д. Например, давайте рассмотрим простое приложение, в котором есть два действия, каждое из которых имеет собственную ViewModel. Наблюдая за значением данных в реальном времени, первое действие переходит ко второму. Но проблема в том, что когда пользователь нажимает кнопку «Назад» во втором действии или когда пользователь возобновляет первое действие из фонового состояния, тогда значение данных в реальном времени переносится в первое действие, которое снова переходит ко второму действию. В результате пользователь никогда не сможет вернуться к первому действию.

Итак, вот в чем суть: как создать LiveData, которая генерирует одно событие и уведомляет только одного наблюдателя, даже если на него подписано несколько наблюдателей?

Решение

Существует класс-оболочка LiveEvent, который решает подобные сценарии. Это LiveData, которая отправляет обновление только один раз. Это расширение MediatorLiveData , которое удобно при обновлении одного наблюдателя, когда за ним наблюдают многие наблюдатели.

Давайте разберемся с этим лучше на примере

Пример

Например, давайте рассмотрим простое приложение для телешоу, в котором есть действие, состоящее из двух фрагментов. FragmentShowsList отображает список шоу, и после щелчка по шоу в FragmentShowsList мы перейдем к FragmentShowDetails, где отображаются подробности шоу. Но что, если бы в обоих фрагментах было общее действие кнопки (например, SUBSCRIBE) , где при нажатии этой кнопки мы вызываем API подписки и публикуем результат с помощью LiveData? Поскольку один и тот же экземпляр LiveData наблюдается в обоих фрагментах после получения результата, нам нужно показать диалог успеха в случае FragmentShowsList и всплывающее сообщение в случае FragmentShowDetails.

Но проблема возникает, когда мы наблюдаем один экземпляр ViewModel. Если FragmentShowsList находится наверху, он получает результат и показывает диалог. Но позже, если мы перейдем к FragmentShowDetails, всплывающее сообщение будет отображаться без нажатия на кнопку, потому что он наблюдает за LiveData, содержащим значение.

Наша деятельность будет выглядеть так:

Его XML выглядит так:

Теперь давайте создадим файл макета fragment_shows_list :

Затем давайте создадим FragmentShowsList:

Теперь давайте создадим FragmentShowDetails:

И fragment_shows_details:

Теперь давайте запустим и проверим вывод:

На что обратить внимание

  1. Я нажал кнопку подписки на FragmentShowList. По результату он показал подтверждение диалога об успешном выполнении, чего и следовало ожидать.
  2. Когда я нажал кнопку навигации, он перешел к FragmentShowDetails, но неожиданно также отобразил всплывающее сообщение, которое не ожидалось или не требовалось.
  3. Когда я щелкнул BackPress на FragmentShowDetails, он был заменен на FragmentShowList, но показал диалог успеха, который не требовался, или случай дублирования.

Чтобы общаться между двумя разными фрагментами внутри действия, мы обычно используем общую ViewModel действия, чтобы исключить шаблонный код с интерфейсом. Но сценарии, подобные описанному выше, вызывают неожиданное поведение, если с ними не обращаться правильно.

Теперь давайте добавим в наш код класс LiveEvent, изменим две строки кода в ViewModel и увидим волшебство:

В коде действия или фрагментов нечего было менять - просто изменили две строчки кода в ViewModel:

Понимание скрытой магии

Причина волшебства выше MediatorLiveData . Его можно определить как подкласс LiveData, который может наблюдать за другими объектами LiveData и реагировать на их события OnChanged. В этом LiveEvent классе мы оборачиваем наблюдателя ObserverWrapper классом , в котором написана фактическая логика. Существует логическое значение, указывающее, наблюдается ли изменение хотя бы один раз.

Заключение

На этом пока все. Итак, кто сталкивался с подобной проблемой с LiveData? Пожалуйста, прокомментируйте. Надеюсь, вы нашли хорошее решение.

Пожалуйста, дайте мне знать ваши предложения.

Спасибо за прочтение.