Что такое live data android

Урок 2. LiveData

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

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

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

В 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.

Как видите, подписывать 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 для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Урок 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 и постить их своим получателям.

Читайте также:  Smart screen off android

Подпишемся на 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 для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Изучаем LiveData в Android: postValue или setValue?

Разработчикам Android часто приходится иметь дело с различными данными. Данные с одного экрана могут использоваться на другом. А ещё можно поменять внешний вид экрана, если данные обновились. Основная задача состоит в том, чтобы наладить эффективное взаимодействие между экраном и источником данных. Лучший способ это сделать — использовать LiveData, которая является частью Android Jetpack.

Чаще всего в LiveData используют методы setValue и postValue. Если судить по названию, кажется, что они выполняют одинаковую работу. Но на самом деле это не так.

Давайте разбираться, в чём разница.

Что такое LiveData?

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

Если говорить простыми словами, LiveData — это контейнер, который следит за жизненным циклом экрана и снабжает его данными, когда это уместно. Например, если активити находится на переднем плане и видна пользователю. Ценность такого подхода заключается в том, что LiveData не будет снабжать ваш экран данными, если он свёрнут или закрыт. Но как только экран появится перед пользователем, обновление данных возобновится.

Это даёт LiveData несколько преимуществ:

  • нет утечек памяти;
  • экран всегда содержит актуальные данные;
  • никаких крашей из-за обновления данных, если активити закрывается.

Разница между setValue и postValue

Разберём на примере, зачем нужны такие похожие методы. Предположим, вам нужно обновить данные на экране с помощью LiveData. Вы можете сделать это в основном потоке приложения (Main thread) или в отдельном. При обновлении в основном потоке вы используете setValue у класса MutableLiveData. А при обновлении данных для основного потока из фонового нужно использовать метод postValue. Это значит, что метод setValue уместен в основном потоке приложения, а postValue — если данные приходят из фонового потока.

Читайте также:  Мультимедийная система для андроида

Вот чек-лист, чтобы не запутаться, когда какой метод нужен:

  • Если вы выполняете работу в основном потоке, то setValue и postValue будут работать одинаково.
  • Если вы выполняете работу в фоновом потоке, то можете использовать только postValue. Дело в том, что данные в LiveData изменятся сразу, а вот их обновление в основном потоке будет происходить асинхронно при помощи Handler.

В коде это будет выглядеть так:

Здесь для разных потоков используются разные методы. Метод setValue вызывается два раза. Это значит, что экран обновится дважды, потому что код выполняется в основном потоке приложения. Метод postValue выполняется асинхронно, поэтому обновление экрана будет зависеть от работы основного потока.

Иногда во время вызова метода liveData.postValue(«someNewData») экран ещё не открыт или приложение свёрнуто. А во время выполнения метода liveData.postValue(«againNewData») экран уже виден пользователю. Это значит, что на экране отобразятся только последние данные «againNewData» .

При использовании postValue будьте внимательны. Если на эту LiveData никто не был подписан во время обновления данных, то вызов getValue их вам не вернёт.

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

Разработчикам Android часто приходится иметь дело с различными данными. Данные с одного экрана могут использоваться на другом. А ещё можно поменять внешний вид экрана, если данные обновились. Основная задача состоит в том, чтобы наладить эффективное взаимодействие между экраном и источником данных. Лучший способ это сделать — использовать LiveData, которая является частью Android Jetpack.

Чаще всего в LiveData используют методы setValue и postValue. Если судить по названию, кажется, что они выполняют одинаковую работу. Но на самом деле это не так.

Давайте разбираться, в чём разница.

Что такое LiveData?

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

Если говорить простыми словами, LiveData — это контейнер, который следит за жизненным циклом экрана и снабжает его данными, когда это уместно. Например, если активити находится на переднем плане и видна пользователю. Ценность такого подхода заключается в том, что LiveData не будет снабжать ваш экран данными, если он свёрнут или закрыт. Но как только экран появится перед пользователем, обновление данных возобновится.

Это даёт LiveData несколько преимуществ:

  • нет утечек памяти;
  • экран всегда содержит актуальные данные;
  • никаких крашей из-за обновления данных, если активити закрывается.

Разница между setValue и postValue

Разберём на примере, зачем нужны такие похожие методы. Предположим, вам нужно обновить данные на экране с помощью LiveData. Вы можете сделать это в основном потоке приложения (Main thread) или в отдельном. При обновлении в основном потоке вы используете setValue у класса MutableLiveData. А при обновлении данных для основного потока из фонового нужно использовать метод postValue. Это значит, что метод setValue уместен в основном потоке приложения, а postValue — если данные приходят из фонового потока.

Вот чек-лист, чтобы не запутаться, когда какой метод нужен:

  • Если вы выполняете работу в основном потоке, то setValue и postValue будут работать одинаково.
  • Если вы выполняете работу в фоновом потоке, то можете использовать только postValue. Дело в том, что данные в LiveData изменятся сразу, а вот их обновление в основном потоке будет происходить асинхронно при помощи Handler.

В коде это будет выглядеть так:

Здесь для разных потоков используются разные методы. Метод setValue вызывается два раза. Это значит, что экран обновится дважды, потому что код выполняется в основном потоке приложения. Метод postValue выполняется асинхронно, поэтому обновление экрана будет зависеть от работы основного потока.

Иногда во время вызова метода liveData.postValue(«someNewData») экран ещё не открыт или приложение свёрнуто. А во время выполнения метода liveData.postValue(«againNewData») экран уже виден пользователю. Это значит, что на экране отобразятся только последние данные «againNewData» .

При использовании postValue будьте внимательны. Если на эту LiveData никто не был подписан во время обновления данных, то вызов getValue их вам не вернёт.

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

Источник

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