Android live data example

Урок 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, и все его активные подписчики получат это обновление.

Читайте также:  Android mkt что это

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

Подпишемся на 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.

Читайте также:  Телевизоры full hd с android tv

Чтобы его использовать добавьте в 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 live data example

Android LiveData & Examples

June 29, 2017 by Srinivas

LiveData is provided as a part of android architectural components. LiveData is an observable which can hold and emit data to the subscribed observers. LiveData is similar to RxJava observable with one difference, LiveData is lifecycle aware, this feature allows it to clean up references when the lifecycle state of the component that observer associated with is destroyed.

Android architectural components allow you to build lifecycle aware components. LiveData is a lifecycle aware observable. When observer subscribes to LiveData, lifecycle of the component that observer belong to, is passed to LiveData. As long as the component is active, observer will receive data from LiveData.

In this article, I’ll explain live data in detail with examples.

Add Libraries

To use LiveData, you need to add libraries related to architectural components to your project. Since these libraries are stored in google maven repository, first we need to add this repository to project build.gradle file as shown below.

Add below dependencies to module build.gradle file.

Android LiveData Advantages

LiveData holds data and emits the data to observers. Whenever the data that LiveData holds changes, LiveData will emit the latest value to its observers. In your app, if there is a feature that depends on certain data which changes frequently, then you can implement the feature using LiveData.

One main point that needs to be noted is that LiveData is lifecycle aware so it can clean references to observers when the lifecycle of the component, activity or fragment, that observer is associated with is destroyed, that means LiveData doesn’t cause memory leaks. So, you don’t need to worry about the code related to starting and stopping observers in response to the lifecycle events.

And also, LiveData has callback methods onActive and onInactive which get called depending on the number of observers added to LiveData and lifecycle states, when number of observers change from 0 to 1, onActive method is called and when the number of observers change from 1 to 0 onInactive method is called. These callback methods can be used to free up resource-intensive objects when component becomes inactive and recreate them when component becomes active.

When a task needs to be run in the background and UI needs to be updated with the results returned from background task, AsyncTask used to be the solution. But the problem with AsyncTask is that since it is tightly coupled to activity class, activity can’t be destroyed in response to life cycle events when AsyncTask is running. By using LiveData, you can solve the problem of memory leaks which can occur with AsyncTask.

Using Android LiveData

Below are the steps to use LiveData in android apps.

  • First create a data model class which holds data.
  • Create your repository class which gets data from either local data base or remote service and returns LiveData object which holds data of data model class type. Value can be set to LiveData using setValue method in main thread and postValue method from non-main thread.
  • You need to identify event which requires a call to repository to get data, the event can be user events like button click or system events from system service like location manager.
  • You need to identify an event which starts observing data from LiveData by adding observer to LiveData passing lifecycle. Usually, observer is added to LiveData in onCreate method of activity.
  • Observer gets called whenever data is changed, and observer gets removed when lifecycle is in destroyed state.
Читайте также:  Виртуальная женщина для андроида

Android LiveData Example

In the below example LiveData is used to hold time and whenever a button on the screen is clicked, LiveData is updated with the latest time. Observer is added to live data, which updates UI with latest time.

Below code creates and sets value to LiveData.

Observer is added to LiveData in onCreate method and onclick of a button, latest time is set to LiveData. Observer updates the UI with latest time.

Android LiveData Retrofit Example

With the below example, I want to show how retrofit and LiveData can be used together and how to update UI from background thread using LiveData without needing to write clean up code to prevent memory leaks.

In this example, rest service call is made asynchronously using retrofit to get data from server, then, in the background thread, the response is set to LiveData and finally observer updates the UI, in the android main thread, with the data from the response.

In retrofit asynchronous call, http request is made on the background thread, but Callback code is run on android main thread. Since I want to show how to update UI from background thread using LiveData, we need to make retrofit run callback on background thread by setting callbackExecutor on retrofit builder.

To set value on LiveData from background thread, we need to use postValue method, not setValue. If you use setValue from background thread, you will get exception: “ java.lang.IllegalStateException: Cannot invoke setValue on a background thread “.

This example requires INTERNET permission and below dependencies.

Retrofit API

Model Class

Retrofit Service

Activity

LiveData with ViewModel

In the above examples, we used static variables for LiveDaata, that means LiveData object will be available till app is closed. We don’t want that, we need LiveData to be available as long as activity or fragment it is associated with exists. To fix this, we need to use ViewModel. ViewModel is lifecycle aware architecture component, that can exist till activity or fragment is destroyed. You can read How to use LiveData and ViewModel with example article.

MediatorLiveData

So far, we learned what LiveData is, what the advantages in using live data are, how to use it in your app, how to use live data with retrofit and how to update LiveData from background thread. In the examples, we used android LiveData implementation MutableLiveData.

One more implementation that comes with the library is MediatorLiveData. MediatorLiveData can be used to decouple observer and LiveData. MediatorLiveData lets you add LiveData and observer to it and it calls the observer when the data that corresponding LiveData holds changes. Using MediatorLiveData you can create LiveData chain to filter, merge, group, and modify data emitted by source LiveData. See Transformation section below for more details.

You can add LiveData to MediatorLiveData by calling addSource method passing LiveData and Observer.

Custom LiveData

You can create custom LiveData by extending LiveData class and implementing abstract methods. Below example shows how to create custom LiveData class called ConnectivityLiveData.

ConnectivityLiveData uses ConnectivityManager to get network information. In onActive method, listener is added to connectivity manager. The listener callback methods are called based on network availability, and the received network data is posted to LiveData. Since these callback methods are called on background thread, we need to use postValue method to set data.

Custom LiveData Example

Activity

LiveData Operators or Transformations

Like RxJava operators which can merge, filter, transform, group and modify observables, transformations can be used to do the same with LiveData. Transformations allow you to operate on data emitted by LiveData before it is passed to observer.

Lifecycle is carried thru the chain of transformations so that transformation and data notification happens only if active observers exist.

There are two transformations provided as part of the lifecycle library, map and switchMap.

Map transformation allows you to apply function on data emitted by source LiveData. Map returns LiveData which emits data returned by the function.

For example, we can apply map on the LiveData from the first example above and modify the value, the resulting live data will emit this modified value.

SwitchMap transformation is similar to map transformation, it applies function to each value emitted by source LiveData, but function itself returns LiveData.

About

Android app development tutorials and web app development tutorials with programming examples and code samples.

Источник

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