pexels-photo

Продолжение

Обновление объектов LiveData

LiveData не имеет общедоступных методов обновления хранимых данных. Класс MutableLiveData предоставляет методы setValue(T) и postValue(T), и вы должны использовать их, если вам нужно отредактировать значение, хранящееся в объекте LiveData. Обычно MutableLiveData используется в ViewModel, а затем ViewModel предоставляет только неизменные (immutable) объекты LiveData для наблюдателей.

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

Вызов setValue(T) в примере приводит к тому, что наблюдатели вызывают свои методы onChanged() со значением John Doe. В этом примере показано нажатие кнопки, но функция setValue () или postValue () может быть вызвана для обновления mName по целому ряду причин, в том числе в ответ на сетевой запрос или завершение загрузки базы данных; во всех случаях вызов setValue () или postValue () запускает наблюдатели и обновляет пользовательский интерфейс.

Примечание. Вы должны вызвать метод setValue(T) для обновления объекта LiveData из основного потока. Если код выполняется в рабочем потоке, вы можете использовать метод postValue(T), чтобы обновить объект LiveData.

Использование LiveData with Room

Библиотека Room persistence library поддерживает наблюдаемые запросы, которые возвращают объекты LiveData. Наблюдаемые запросы записываются как часть объекта доступа к базе данных (DAO).

Room генерирует весь необходимый код для обновления объекта LiveData при обновлении базы данных. Сгенерированный код выполняет запрос асинхронно в фоновом потоке, когда это необходимо. Этот шаблон полезен для сохранения данных, отображаемых в пользовательском интерфейсе, в синхронизации с данными, хранящимися в базе данных. Вы можете больше узнать о Room и DAO в Room persistent library guide.

Расширение LiveData

LiveData считает, что наблюдатель находится в активном состоянии, если жизненный цикл наблюдателя находится в состояниях STARTED или RESUMED. Следующий пример кода иллюстрирует, как расширить класс LiveData:

Реализация слушателя в этом примере включает следующие важные методы:

  • Метод onActive() вызывается, когда объект LiveData имеет активного наблюдателя. Это означает, что вам необходимо начать наблюдать за обновлением (цен на акции) с помощью этого метода.
  • Метод onInactive () вызывается, когда объект LiveData не имеет активных наблюдателей. Поскольку ни один из наблюдателей не слушает, нет причин оставаться на связи со службой StockManager.
  • Метод setValue (T) обновляет значение экземпляра LiveData и уведомляет всех активных наблюдателей об изменении.

Вы можете использовать класс StockLiveData следующим образом:

Метод observe() передает в качестве первого аргумента фрагмент, который является экземпляром LifecycleOwner. Это означает, что этот наблюдатель привязан к объекту Lifecycle, связанному с владельцем, что означает:

  • Если объект Lifecycle не находится в активном состоянии, то наблюдатель не вызывается, даже если значение изменяется.
  • После уничтожения объекта Lifecycle наблюдатель автоматически удаляется.

Тот факт, что объекты LiveData являются ориентированными на жизненный цикл, означает, что вы можете делиться ими между несколькими действиями, фрагментами и службами. Чтобы упростить пример, вы можете реализовать класс LiveData как синглтон:

И вы можете использовать его в фрагменте следующим образом:

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

Трансформация LiveData

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

Пакет Lifecycle предоставляет класс Transformations, который включает вспомогательные методы, поддерживающие эти сценарии.

Transformations.map()

Применяет функцию к значению, хранящемуся в объекте LiveData, и передает результат вниз по течению.

Подобно map (), применяет функцию к значению, хранящемуся в объекте LiveData, и разворачивает и отправляет результат вниз по течению. Функция, переданная switchMap (), должна возвращать объект LiveData, как показано на следующем примере:

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

Если вы считаете, что вам нужен объект Lifecycle внутри объекта ViewModel, преобразование, вероятно, является лучшим решением.

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

Компонент пользовательского интерфейса затем должен отменить регистрацию из предыдущего объекта LiveData и зарегистрироваться в новом экземпляре каждый раз, когда он вызывает getPostalCode (). Кроме того, если компонент UI воссоздан, он вызывает другой вызов метода repository.getPostCode () вместо использования результата предыдущего вызова.

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

В этом случае поле postalCode является общедоступным и окончательным, поскольку поле никогда не изменяется. Поле postalCode определяется как преобразование addressInput, что означает, что метод repository.getPostCode() вызывается при изменении addressInput. Это верно, если есть активный наблюдатель, если нет активных активных наблюдателей в момент вызова repository.getPostCode() то вычисления не выполняются, пока не будет добавлен наблюдатель.

Этот механизм позволяет более низким уровням приложения создавать объекты LiveData, которые лениво вычисляются по требованию. Объект ViewModel может легко получать ссылки на объекты LiveData, а затем определять правила преобразования поверх них.

Создание новых преобразований

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

Слияние нескольких источников LiveData

MediatorLiveData — это подкласс LiveData, который позволяет объединить несколько источников LiveData. Наблюдатели объектов MediatorLiveData затем запускаются всякий раз, когда изменяется исходный объект исходного объекта LiveData.

Например, если у вас есть объект LiveData в пользовательском интерфейсе, который может быть обновлен из локальной базы данных или сети, то вы можете добавить следующие объекты в объект MediatorLiveData:

  • Объект LiveData, связанный с данными, хранящимися в базе данных.
  • Объект LiveData, связанный с данными, доступными из сети.

В вашей  активности потребуется только наблюдать объект MediatorLiveData для получения обновлений из обоих источников. Подробный пример см  Addendum: exposing network status section of the Guide to App Architecture.

 

Продолжение следует…