Mutablelivedata android что это

Урок 3. LiveData. Дополнительные возможности

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

Полный список уроков курса:

Transformations

Рассмотрим пример, в котором LiveData будем превращать в LiveData :

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

На выходе метода map получим LiveData . Можно сказать, что он подписан на LiveData и все получаемые String значения будет конвертировать в Integer и рассылать уже своим подписчикам.

Рассмотрим более сложный случай. У нас есть LiveData , нам необходимо из него получить LiveData . Конвертация id в User выглядит так:

По id мы получаем LiveData и на него надо будет подписываться, чтобы получить объект User.

В этом случае мы не можем использовать метод map, т.к. мы получим примерно такой результат:

switchMap уберет вложенность LiveData и мы получим LiveData .

Свой LiveData

В некоторых ситуациях удобно создать свою обертку LiveData.

Класс LocationLiveData расширяет LiveData .

Внутри него есть некий locationListener — слушатель, который можно передать в LocationService и получать обновления текущего местоположения. При получении нового Location от LocationService, locationListener будет вызывать метод setValue и тем самым обновлять данные этого LiveData.

LocationService — это просто какой-то сервис, который предоставляет нам текущую локацию. Его реализация в данном примере не важна. Главное — это то, что мы подписываемся (addListener) на сервис, когда нам нужны данные, и отписываемся (removeListener), когда данные больше не нужны.

Обратите внимание, что мы переопределили методы onActive и onInactive. onActive будет вызван, когда у LiveData появится хотя бы один подписчик. А onInactive — когда не останется ни одного подписчика. Соответственно эти методы удобно использовать для подключения/отключения нашего слушателя к LocationService.

Получилась удобная обертка, которая при появлении подписчиков сама будет подписываться к LocationService, получать Location и передавать его своим подписчикам. А когда подписчиков не останется, то LocationLiveData отпишется от LocationService.

Осталось сделать из LocationLiveData синглтон и можно использовать его в разных Activity и фрагментах.

MediatorLiveData

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

Рассмотрим, как это делается, на простом примере.

У нас есть два LiveData : liveData1 и liveData2. Мы хотим объединить их в один. Для этого нам понадобится MediatorLiveData.

Добавляем LiveData к MediatorLiveData

Первый — это LiveData из которого MediatorLiveData собирается получать данные.

Второй параметр — это колбэк, который будет использован для подписки на LiveData из первого параметра. Обратите внимание, что в колбэке нам надо самим передавать в MediatorLiveData данные, получаемые из LiveData. Это делается методом setValue.

Таким образом mediatorLiveData будет получать данные из двух LiveData и постить их своим получателям.

Подпишемся на mediatorLiveData

Сюда теперь должны приходить данные из liveData1 и liveData2. Будем их просто логировать.

Отправим данные в liveData1 и liveData2:

Все данные, что мы передавали в liveData1 и liveData2 пришли в общий mediatorLiveData.

Немного усложним пример. Допустим, нам надо отписаться от liveData2, когда из него придет значение «finish».

Читайте также:  Битва кланов для андроид

Код подписки mediatorLiveData на liveData1 и liveData2 будет выглядеть так:

В случае с liveData1 ничего не меняется.

А вот при получении данных от liveData2 мы смотрим, что за значение пришло. Если это значение «finish», то методом )» target=»_blank» rel=»noopener noreferrer»>removeSource отписываем mediatorLiveData от liveData2 и не передаем это значение дальше.

Отправим несколько значений

liveData2 отправляет здесь значения «a», «finish», «b» и «c». Через mediatorLiveData должно пройти только «a». А значение из liveData1 должны пройти все.

Запускаем, смотрим лог:

Все верно. При получении «finish» от liveData2, mediatorLiveData отписался от него и последующие его данные мы уже не получали.

RxJava

Мы можем конвертировать LiveData в Rx и наоборот. Для этого есть инструмент LiveDataReactiveStreams.

Чтобы его использовать добавьте в dependencies:

Чтобы получить LiveData из Flowable или Observable, используем метод )» target=»_blank» rel=»noopener noreferrer»>fromPublisher:

LiveData будет подписан на Flowable, пока у него (у LiveData) есть подписчики.

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

Неважно в каком потоке работает Flowable, результат в LiveData всегда придет в UI потоке.

Чтобы получить Flowable или Observable из LiveData нужно выполнить два преобразования. Сначала используем метод )» target=»_blank» rel=»noopener noreferrer»>toPublisher, чтобы получить Publisher. Затем полученный Publisher передаем в метод Flowable.fromPublisher:

Прочие методы LiveData

hasActiveObservers() — проверка наличия активных подписчиков

hasObservers() — проверка наличия любых подписчиков

)» target=»_blank» rel=»noopener noreferrer»>observeForever (Observer observer) — позволяет подписаться без учета Lifecycle. Т.е. этот подписчик будет всегда считаться активным.

removeObservers (LifecycleOwner owner) — позволяет отписать всех подписчиков, которые завязаны на Lifecycle от указанного LifecycleOwner.

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Android LiveData на Kotlin с использованием Retrofit и coroutines

Так же рассмотрен пример применения современного Coroutines в связке с репозитарием на Retrofit

Retrofit coroutines extension

kotlin-coroutines-retrofit
Расширение для Retrofit на Kotlin. Это всего два файла. Я просто добавил их в проект. Вы можете подключить их через Dependency в Gradle. На Github есть примеры использования.
Также подключаем Adapter addCallAdapterFactory(CoroutineCallAdapterFactory()).
ServerAPI и Repository находятся в одном файле

Реализацией REST API на Kotlin. Она не имеет каких либо специфичных изменений

Далее рассмотрим Repository. Это основной сервис получения LiveData. Инициализируем LiveData состоянием загрузки: Resource.loading(null). Далее ожидаем окончание запроса awaitResult() Этот вызов должен быть в блоке Coroutin async(UI)

По окончанию запроса мы можем хэндлить результат. Если все хорошо результат будет сохранен в mutableLiveData.value = Resource.success(result.value) Важный момент — это должена быть ссылка на новый экземпляр, иначе observer LiveData не отработает. see: new Resource<>(SUCCESS, data, null);

Для обработки ошибок и передачи состояния в Fragment используется Wrapper — Resource .

Он хранить три состояния:

StoresViewModel запрашивает данные у репозитория и сохраняет во внутренней переменной stores

Для передачи параметров в ViewModel расширим стандартную ViewModelProviders
Например для передачи в LoginViewModel надо два параметра (Login,Password). Для передачи токена в StoresViewModel используется один (Token)

Использование наблюдателя Observer за изменением данных:

Для хранения Token и использования его во всем приложении я применил библиотеку/расширение от Fabio Collini. Применение хорошо описано в его статье. Ссылка есть на странице в Github или ниже в этой статье.

Источник

Урок 2. LiveData

В этом уроке рассмотрим основные возможности LiveData. Как подписаться на его данные. Как помещать в него данные. Как он взаимодействует со своими подписчиками.

Читайте также:  Android 4 acer a500 февраль

Полный список уроков курса:

Подключение библиотеки

В build.gradle файл проекта добавьте репозитарий google()

В build.gradle файле модуля добавьте dependencies:

Если у вас студия ниже 3.0 и старые версии Gradle и Android Plugin, то подключение будет выглядеть так:

Иногда может возникнуть конфликт с support library. Будет выдавать такую ошибку: Error:Program type already present: android.arch.lifecycle.LiveData

В таком случае попробуйте указать последние версии двух этих библиотек.

Теория

LiveData — хранилище данных, работающее по принципу паттерна Observer (наблюдатель). Это хранилище умеет делать две вещи:

1) В него можно поместить какой-либо объект

2) На него можно подписаться и получать объекты, которые в него помещают.

Т.е. с одной стороны кто-то помещает объект в хранилище, а с другой стороны кто-то подписывается и получает этот объект.

В качестве аналогии можно привести, например, каналы в Telegram. Автор пишет пост и отправляет его в канал, а все подписчики получают этот пост.

Если вы знакомы с RxJava, то LiveData напомнит вам BehaviourSubject. Методом onNext вы передаете ему данные, а он передает эти данные своим подписчикам. Плюс, все новые подписчики сразу получают последнее значение.

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

Получение данных из LiveData

Давайте рассмотрим пример.

Пусть у нас есть некий синглтон класс DataController из которого можно получить LiveData .

DataController периодически что-то там внутри себя делает и обновляет данные в LiveData. Как он это делает, мы посмотрим чуть позже. Сначала посмотрим, как Activity может подписаться на LiveData и получать данные, которые помещает в него DataController.

Код в Activity будет выглядеть так:

Получаем LiveData из DataController, и методом )» target=»_blank» rel=»noopener noreferrer»>observe подписываемся. В метод observe нам необходимо передать два параметра:

Первый — это LifecycleOwner. Напомню, что LifecycleOwner — это интерфейс с методом getLifecycle. Activity и фрагменты в Support Library, начиная с версии 26.1.0 реализуют этот интерфейс, поэтому мы передаем this.

LiveData получит из Activity его Lifecycle и по нему будет определять состояние Activity. Активным считается состояние STARTED или RESUMED. Т.е. если Activity видно на экране, то LiveData считает его активным и будет отправлять данные в его колбэк.

Если предыдущие два абзаца состоят из кучи незнакомых для вас слов, то посмотрите Урок 1. Lifecycle. Там мы подробно разобрали объект Lifecycle и его состояния.

Второй параметр — это непосредственно подписчик, т.е. колбэк, в который LiveData будет отправлять данные. В нем только один метод onChanged. В нашем примере туда будет приходить String.

Теперь, когда DataController поместит какой-либо String объект в LiveData, мы сразу получим этот объект в Activity, если Activity находится в состоянии STARTED или RESUMED.

Нюансы поведения

Распишу сразу несколько важных моментов в поведении LifeData.

Если Activity было не активно во время обновления данных в LiveData, то при возврате в активное состояние, его observer получит последнее актуальное значение данных.

В момент подписки, observer получит последнее актуальное значение из LiveData.

Если Activity будет закрыто, т.е. перейдет в статус DESTROYED, то LiveData автоматически отпишет от себя его observer.

Если Activity в состоянии DESTROYED попробует подписаться, то подписка не будет выполнена.

Если Activity уже подписывало свой observer, и попробует сделать это еще раз, то просто ничего не произойдет.

Вы всегда можете получить последнее значение LiveData с помощью его метода getValue.

Читайте также:  How to flash android phone

Как видите, подписывать Activity на LiveData — это удобно. Поворот экрана и полное закрытие Activity — все это корректно и удобно обрабатывается автоматически без каких-либо усилий с нашей стороны.

Отправка данных в LiveData

Мы разобрались, как получать данные из LiveData, и каким образом при этом учитывается состояние Activity. Теперь давайте посмотрим с другой стороны — как передавать данные в LiveData.

В классе DataController переменная LiveData будет выглядеть так:

Наружу мы передаем LiveData, который позволит внешним объектам только получать данные. Но внутри DataController мы используем объект MutableLiveData, который позволяет помещать в него данные.

Чтобы поместить значение в MutableLiveData, используется метод setValue:

Этот метод обновит значение LiveData, и все его активные подписчики получат это обновление.

Метод setValue должен быть вызван из UI потока. Для обновления данных из других потоков используйте метод postValue. Он перенаправит вызов в UI поток. Соответственно, подписчики всегда будут получать значения в основном потоке.

Чуть более подробный пример с LiveData мы рассмотрим в Уроке 4, когда будем изучать ViewModel.

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

События на базе LiveData Android

LiveData – это отличный инструмент для связывания состояния ваших данных и объектов с жизненным циклом (LifecycleOwner, обычно это Fragment или Activity).

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

Но что, если мы хотим использовать механизм событий, а не состояний? Причем обязательно в контексте жизненного цикла обозревателя (LifecycleOwner). Например, нам нужно вывести сообщение после асинхронной операции при условии, что LifecycleOwner еще жив, имеет активных обозревателей и готов обновить свой UI. Если мы будем использовать LiveData, то мы будем получать одно и то же сообщение после каждой смены конфигурации, или при каждом новом подписчике. Одно из решений, которое напрашивается, это после обработки данных в некотором обозревателе обнулить эти данные в LiveData.

Например, такой код:

Но такой подход имеет ряд недостатков и не отвечает всем необходимым требованиям.

Мне бы хотелось иметь механизм событий, который:

  1. оповещает только активных подписчиков,
  2. в момент подписки не оповещает о предыдущих данных,
  3. имеет возможность выставить флаг handled в true, чтобы прервать дальнейшую обработку события.

Я реализовал класс MutableLiveEvent, который обладает всеми вышеперечисленными свойствами и который может работать, как обычный LiveData.

Весь код доступен на GitHub, а ниже я немного расскажу о реализации.

Идея заключается в том, чтобы внутри класса MutableLiveEvent, в методах observe и observeForever, оборачивать обозреватели в специальный внутренний класс PendingObserver, который вызывает реальный обозреватель только один раз и только если выставлен флаг pending в true, и событие еще не обработано.

В PendingObserver флаг pending выставлен в false по умолчанию. Это решает п.2 (не оповещать о старых данных) из нашего списка.

А код в MutableLiveEvent

Сначала выставляет pending в true и только потом обновляет данные внутри себя. Это обеспечивает выполнение п.1. (оповещение только активных подписчиков).

Последний момент, о котором я еще не рассказал, — это EventArgs. Это класс — обобщение, в котором есть флаг handled для прерывания дальнейшей обработки события (п.3.).

Источник

Оцените статью