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

 


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


 

 

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

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

allprojects {
    repositories {
        jcenter()
        google()
    }
    ...
}

 

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

dependencies {
    implementation "android.arch.lifecycle:extensions:1.0.0"
    annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
    ...
}

 

 

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

buildscript {
    repositories {
        jcenter()
        maven { url 'https://maven.google.com' }
    }
    ...
}

и так:

dependencies {
    compile "android.arch.lifecycle:extensions:1.0.0"
    annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
    ...
}

   

Иногда может возникнуть конфликт с 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<String>.

LiveData<String> liveData = DataController.getInstance().getData();

 

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

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

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   
   LiveData<String> liveData = DataController.getInstance().getData();

   liveData.observe(this, new Observer<String>() {
       @Override
       public void onChanged(@Nullable String value) {
           textView.setText(value)
       }
   });
}

Получаем LiveData из DataController, и методом 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 будет выглядеть так:

private MutableLiveData<String> liveData = new MutableLiveData<>();

LiveData<String> getData() {
   return liveData;
} 

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

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

liveData.setValue("new value");

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

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

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


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

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

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

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

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




Language

Социальные сети

 

Telegram канал



Android чат в Telegram



Группа ВКонтакте



Поддержка проекта

Яндекс
410011180491924

WebMoney
R248743991365
Z551306702056

Paypal