Основы Android Kotlin 05.2: LiveData и наблюдатели LiveData

Эта практическая работа входит в курс «Основы Android Kotlin». Вы получите максимальную пользу от этого курса, если будете выполнять практические работы последовательно. Все практические работы курса перечислены на целевой странице практической работы «Основы Android Kotlin» .

Введение

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

Чтобы использовать класс LiveData , необходимо настроить «наблюдатели» (например, действия или фрагменты), которые отслеживают изменения данных приложения. LiveData учитывает жизненный цикл, поэтому обновляет только наблюдателей компонентов приложения, находящихся в активном состоянии жизненного цикла.

Что вам уже следует знать

  • Как создавать простые приложения для Android на Kotlin.
  • Как перемещаться между пунктами назначения вашего приложения.
  • Жизненный цикл активности и фрагмента.
  • Как использовать объекты ViewModel в вашем приложении.
  • Как создавать объекты ViewModel с помощью интерфейса ViewModelProvider.Factory .

Чему вы научитесь

  • Что делает объекты LiveData полезными.
  • Как добавить LiveData к данным, хранящимся в ViewModel .
  • Когда и как использовать MutableLiveData .
  • Как добавить методы наблюдателя для наблюдения за изменениями в LiveData.
  • Как инкапсулировать LiveData с помощью резервного свойства.
  • Как организовать взаимодействие между контроллером пользовательского интерфейса и соответствующей ему ViewModel .

Что ты будешь делать?

  • Используйте LiveData для определения слова и оценки в приложении GuessTheWord.
  • Добавьте наблюдателей, которые заметят, когда изменится слово или счет.
  • Обновите текстовые представления, отображающие измененные значения.
  • Используйте шаблон наблюдателя LiveData для добавления события завершения игры.
  • Реализуйте кнопку «Воспроизвести снова» .

В практических занятиях по коду Урока 5 вы разработаете приложение GuessTheWord, начав с базового кода. GuessTheWord — это игра в стиле шарады для двух игроков, где игроки объединяют усилия, чтобы набрать как можно больше очков.

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

Чтобы начать игру, первый игрок открывает приложение на устройстве и видит слово, например, «гитара», как показано на снимке экрана ниже.

Первый игрок изображает слово, стараясь не произносить его целиком.

  • Когда второй игрок правильно отгадывает слово, первый игрок нажимает кнопку « Понял» , что увеличивает счет на единицу и показывает следующее слово.
  • Если второй игрок не может угадать слово, первый игрок нажимает кнопку «Пропустить» , что уменьшает счет на единицу и переходит к следующему слову.
  • Чтобы завершить игру, нажмите кнопку «Завершить игру» . (Эта функция отсутствует в стартовом коде первой лабораторной работы в серии.)

В этой лабораторной работе вы улучшите приложение GuessTheWord, добавив событие завершения игры, когда пользователь циклически перебирает все слова в приложении. Вы также добавите кнопку «Играть снова» во фрагмент с результатами, чтобы пользователь мог сыграть в игру ещё раз.

Титульный экран

Игровой экран

Экран результатов

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

  1. (Необязательно) Если вы не используете код из предыдущей лабораторной работы, скачайте начальный код для этой. Распакуйте код и откройте проект в Android Studio.
  2. Запустите приложение и играйте в игру.
  3. Обратите внимание, что кнопка «Пропустить» отображает следующее слово и уменьшает счёт на один, а кнопка « Понял» отображает следующее слово и увеличивает счёт на один. Кнопка «Завершить игру» завершает игру.

LiveData — это класс-хранилище наблюдаемых данных, учитывающий жизненный цикл. Например, вы можете обернуть LiveData вокруг текущего счёта в приложении GuessTheWord. В этой практической работе вы узнаете о нескольких характеристиках LiveData :

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

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

Шаг 1: Измените счет и слово, чтобы использовать LiveData

  1. В пакете screens/game откройте файл GameViewModel .
  2. Измените тип переменных score и word на MutableLiveData .

    MutableLiveData — это класс LiveData , значение которого можно изменять. MutableLiveData — это универсальный класс, поэтому необходимо указать тип хранимых им данных.
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()
  1. В GameViewModel , внутри блока init , инициализируйте score и word . Чтобы изменить значение переменной LiveData , используйте метод setValue() . В Kotlin метод setValue() можно вызвать, используя свойство value .
init {

   word.value = ""
   score.value = 0
  ...
}

Шаг 2: Обновите ссылку на объект LiveData

Переменные score и word теперь имеют тип LiveData . На этом этапе вы изменяете ссылки на эти переменные, используя свойство value .

  1. В методе onSkip() в GameViewModel измените score на score.value . Обратите внимание на ошибку о возможном score в null . Эту ошибку нужно исправить следующим способом.
  2. Чтобы устранить ошибку, добавьте проверку null в score.value в onSkip() . Затем вызовите функцию minus() для score , которая выполнит вычитание с защитой null .
fun onSkip() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.minus(1)
   }
   nextWord()
}
  1. Обновите метод onCorrect() таким же образом: добавьте проверку null к переменной score и используйте функцию plus() .
fun onCorrect() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.plus(1)
   }
   nextWord()
}
  1. В GameViewModel внутри метода nextWord() измените ссылку word на word . value .
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       word.value = wordList.removeAt(0)
   }
}
  1. value. GameFragment внутри метода updateWordText() . . viewModel word viewModel .word
/** Methods for updating the UI **/
private fun updateWordText() {
   binding.wordText.text = viewModel.word.value
}
  1. В GameFragment , внутри метода updateScoreText() , измените ссылку . viewModel .score на viewModel . score value.
private fun updateScoreText() {
   binding.scoreText.text = viewModel.score.value.toString()
}
  1. В методе gameFinished() . .score GameFragment ссылку viewModel null viewModel . Добавьте обязательную проверку score value .
private fun gameFinished() {
   Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
   val action = GameFragmentDirections.actionGameToScore()
   action.score = viewModel.score.value?:0
   NavHostFragment.findNavController(this).navigate(action)
}
  1. Убедитесь, что в вашем коде нет ошибок. Скомпилируйте и запустите приложение. Функциональность приложения должна остаться прежней.

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

  1. В методе GameFragment, onCreateView() присоедините объект Observer к объекту LiveData для текущего счёта viewModel.score . Используйте метод observe() и поместите код после инициализации viewModel . Для упрощения кода используйте лямбда-выражение. ( Лямбда-выражение — это анонимная функция, которая не объявляется, а передаётся непосредственно как выражение.)
viewModel.score.observe(this, Observer { newScore ->
})

Разрешите ссылку на Observer . Для этого выберите Observer , нажмите Alt+Enter ( Option+Enter на Mac) и импортируйте androidx.lifecycle.Observer .

  1. Наблюдатель, который вы только что создали, получает событие при изменении данных, хранящихся в наблюдаемом объекте LiveData . Внутри наблюдателя обновите TextView счёта, указав новый счёт.
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})
  1. Прикрепите объект Observer к текущему объекту LiveData слова. Сделайте это так же, как вы прикрепили объект Observer к текущему счёту.
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
   binding.wordText.text = newWord
})

При изменении значения score или word score или word , отображаемые на экране, теперь обновляются автоматически.

  1. В GameFragment удалите методы updateWordText() и updateScoreText() и все ссылки на них. Они вам больше не понадобятся, поскольку текстовые представления обновляются методами наблюдателя LiveData .
  2. Запустите приложение. Ваше игровое приложение должно работать точно так же, как и раньше, но теперь оно использует LiveData и наблюдателей LiveData .

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

В вашем текущем коде любой внешний класс может изменять переменные score и word , используя свойство value , например, viewModel.score.value . В приложении, которое вы разрабатываете в этой лабораторной работе, это может не иметь значения, но в рабочем приложении вам нужен контроль над данными в объектах ViewModel .

Только ViewModel должна редактировать данные в вашем приложении. Но UI-контроллерам необходимо читать данные, поэтому поля данных не могут быть полностью приватными. Для инкапсуляции данных вашего приложения используются объекты MutableLiveData и LiveData .

MutableLiveData против LiveData :

  • Данные в объекте MutableLiveData , как следует из названия, можно изменять. Внутри ViewModel данные должны быть доступны для редактирования, поэтому используется MutableLiveData .
  • Данные в объекте LiveData можно читать, но нельзя изменять. Извне ViewModel данные должны быть доступны для чтения, но не для редактирования, поэтому они должны быть представлены как LiveData .

Для реализации этой стратегии используется резервное свойство Kotlin. Резервное свойство позволяет возвращать из геттера нечто, отличное от точного объекта. В этой задаче вы реализуете резервное свойство для объектов score и word в приложении GuessTheWord.

Добавить свойство поддержки к партитуре и слову

  1. В GameViewModel сделайте текущий объект score private .
  2. Чтобы следовать соглашению об именовании, используемому в резервных свойствах, измените score на _score . Свойство _score теперь представляет собой изменяемую версию игрового счёта для внутреннего использования.
  3. Создайте публичную версию типа LiveData под названием score .
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
  1. Вы видите ошибку инициализации. Эта ошибка возникает, потому что внутри GameFragment score является ссылкой LiveData , и score больше не может получить доступ к своему сеттеру. Подробнее о геттерах и сеттерах в Kotlin см. в разделе Геттеры и сеттеры .

    Чтобы устранить ошибку, переопределите метод get() для объекта score в GameViewModel и верните резервное свойство _score .
val score: LiveData<Int>
   get() = _score
  1. В GameViewModel измените ссылки score на его внутреннюю изменяемую версию _score .
init {
   ...
   _score.value = 0
   ...
}

...
fun onSkip() {
   if (!wordList.isEmpty()) {
       _score.value = (score.value)?.minus(1)
   }
  ...
}

fun onCorrect() {
   if (!wordList.isEmpty()) {
       _score.value = (score.value)?.plus(1)
   }
   ...
}
  1. Переименуйте объект word в _word и добавьте для него резервное свойство, как вы это делали для объекта score .
// The current word
private val _word = MutableLiveData<String>()
val word: LiveData<String>
   get() = _word
...
init {
   _word.value = ""
   ...
}
...
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       _word.value = wordList.removeAt(0)
   }
}

Отличная работа, вы инкапсулировали объекты LiveData word и score .

Ваше текущее приложение переходит на экран счёта, когда пользователь нажимает кнопку « Завершить игру» . Вы также хотите, чтобы приложение переходило на экран счёта, когда игроки циклически повторяют все слова. После того, как игроки закончат с последним словом, игра должна автоматически завершаться, чтобы пользователю не приходилось нажимать кнопку.

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

Модель наблюдателя

Паттерн «Наблюдатель» — это шаблон проектирования программного обеспечения. Он определяет взаимодействие между объектами: наблюдаемым («субъектом» наблюдения) и наблюдателями . Наблюдаемый — это объект, уведомляющий наблюдателей об изменениях своего состояния.

В случае LiveData в этом приложении наблюдаемым объектом (субъектом) является объект LiveData , а наблюдателями — методы в контроллерах пользовательского интерфейса, например, фрагментах. Изменение состояния происходит при каждом изменении данных, обёрнутых в LiveData . Классы LiveData играют ключевую роль в обмене данными между ViewModel и фрагментом.

Шаг 1: Используйте LiveData для обнаружения события завершения игры

В этой задаче вы используете шаблон наблюдателя LiveData для моделирования события завершения игры.

  1. В GameViewModel создайте объект Boolean MutableLiveData с именем _eventGameFinish . Этот объект будет хранить событие завершения игры.
  2. После инициализации объекта _eventGameFinish создайте и инициализируйте резервное свойство с именем eventGameFinish .
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
   get() = _eventGameFinish
  1. В GameViewModel добавьте метод onGameFinish() . В этом методе установите для события завершения игры eventGameFinish значение true .
/** Method for the game completed event **/
fun onGameFinish() {
   _eventGameFinish.value = true
}
  1. В GameViewModel внутри метода nextWord() завершите игру, если список слов пуст.
private fun nextWord() {
   if (wordList.isEmpty()) {
       onGameFinish()
   } else {
       //Select and remove a _word from the list
       _word.value = wordList.removeAt(0)
   }
}
  1. В GameFragment , внутри onCreateView() , после инициализации viewModel , присоедините наблюдателя к eventGameFinish . Используйте метод observe() . Внутри лямбда-функции вызовите метод gameFinished() .
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
   if (hasFinished) gameFinished()
})
  1. Запустите приложение, сыграйте в игру и пройдите все слова. Приложение автоматически перейдет к экрану счёта, а не останется в игровом фрагменте, пока вы не нажмёте «Завершить игру» .

    После того, как список слов опустеет, устанавливается eventGameFinish , вызывается связанный метод наблюдателя в игровом фрагменте, и приложение переходит к фрагменту экрана.
  2. Добавленный вами код создал проблему жизненного цикла. Чтобы разобраться в проблеме, закомментируйте код навигации в методе gameFinished() класса GameFragment . Убедитесь, что в методе сохранено Toast сообщение.
private fun gameFinished() {
       Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
//        val action = GameFragmentDirections.actionGameToScore()
//        action.score = viewModel.score.value?:0
//        NavHostFragment.findNavController(this).navigate(action)
   }
  1. Запустите приложение, играйте и пройдитесь по всем словам. В нижней части игрового экрана на короткое время появится всплывающее сообщение «Игра только что завершена», что вполне ожидаемо.

Теперь поверните устройство или эмулятор. Уведомление снова появится! Поверните устройство ещё несколько раз, и, вероятно, вы будете видеть уведомление каждый раз. Это ошибка, поскольку уведомление должно появляться только один раз, после завершения игры. Уведомление не должно появляться каждый раз при пересоздании фрагмента. Вы решите эту проблему в следующем задании.

Шаг 2: Сброс события завершения игры

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

Именно поэтому уведомление о завершении игры постоянно запускается в вашем приложении. Когда фрагмент игры пересоздаётся после поворота экрана, он переходит из неактивного состояния в активное. Наблюдатель во фрагменте повторно подключается к существующей ViewModel и получает текущие данные. Метод gameFinished() запускается повторно, и уведомление отображается.

В этой задаче вы исправите эту проблему и отобразите уведомление только один раз, сбросив флаг eventGameFinish в GameViewModel .

  1. В GameViewModel добавьте метод onGameFinishComplete() для сброса события завершения игры, _eventGameFinish .
/** Method for the game completed event **/

fun onGameFinishComplete() {
   _eventGameFinish.value = false
}
  1. В GameFragment , в конце gameFinished() , вызовите onGameFinishComplete() для объекта viewModel . (Пока оставьте код навигации в gameFinished() закомментированным.)
private fun gameFinished() {
   ...
   viewModel.onGameFinishComplete()
}
  1. Запустите приложение и играйте. Прочитайте все слова, а затем измените ориентацию экрана устройства. Уведомление отображается только один раз.
  2. В GameFragment внутри метода gameFinished() раскомментируйте код навигации.

    Чтобы раскомментировать строки в Android Studio, выделите закомментированные строки и нажмите Control+/ ( Command+/ на Mac).
private fun gameFinished() {
   Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
   val action = GameFragmentDirections.actionGameToScore()
   action.score = viewModel.score.value?:0
   findNavController(this).navigate(action)
   viewModel.onGameFinishComplete()
}

Если Android Studio предложит, импортируйте androidx.navigation.fragment.NavHostFragment.findNavController .

  1. Запустите приложение и играйте. Убедитесь, что приложение автоматически перейдёт на экран с итоговым счётом после того, как вы разгадаете все слова.

Отличная работа! Ваше приложение использует LiveData для активации события завершения игры, чтобы сообщить GameViewModel фрагменту игры о том, что список слов пуст. Затем фрагмент игры переходит к фрагменту счёта.

В этой задаче вы преобразуете счёт в объект LiveData в ScoreViewModel и присоединяете к нему наблюдателя. Эта задача аналогична той, что вы выполняли при добавлении LiveData в GameViewModel .

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

  1. В ScoreViewModel измените тип переменной score на MutableLiveData . Переименуйте её по соглашению в _score и добавьте резервное свойство.
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
   get() = _score
  1. В ScoreViewModel , внутри блока init , инициализируйте _score . Вы можете удалить или оставить журнал в блоке init по своему усмотрению.
init {
   _score.value = finalScore
}
  1. В ScoreFragment внутри onCreateView() после инициализации viewModel присоедините наблюдателя для объекта LiveData со счётом. Внутри лямбда-выражения установите значение счёта в текстовом представлении счёта. Удалите код, который напрямую присваивает текстовому представлению значение счёта из ViewModel .

Код для добавления:

// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})

Код для удаления:

binding.scoreText.text = viewModel.score.toString()

При появлении запроса от Android Studio импортируйте androidx.lifecycle.Observer .

  1. Запустите приложение и играйте. Приложение должно работать как и прежде, но теперь оно использует LiveData и наблюдателя для обновления счёта.

В этой задаче вы добавите кнопку «Играть снова» на экран счёта и реализуете её прослушиватель кликов с помощью события LiveData . Кнопка запускает событие для перехода с экрана счёта на экран игры.

Стартовый код приложения включает кнопку «Воспроизвести снова» , но она скрыта.

  1. В res/layout/score_fragment.xml для кнопки play_again_button измените значение атрибута visibility на visible .
<Button
   android:id="@+id/play_again_button"
...
   android:visibility="visible"
 />
  1. В ScoreViewModel добавьте объект LiveData для хранения Boolean _eventPlayAgain . Этот объект используется для сохранения события LiveData для перехода с экрана счёта на экран игры.
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
   get() = _eventPlayAgain
  1. В ScoreViewModel определите методы для установки и сброса события _eventPlayAgain .
fun onPlayAgain() {
   _eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
   _eventPlayAgain.value = false
}
  1. В ScoreFragment добавьте наблюдателя для eventPlayAgain . Поместите код в конец onCreateView() , перед оператором return . Внутри лямбда-выражения вернитесь на игровой экран и сбросьте eventPlayAgain .
// Navigates back to game when button is pressed
viewModel.eventPlayAgain.observe(this, Observer { playAgain ->
   if (playAgain) {
      findNavController().navigate(ScoreFragmentDirections.actionRestart())
       viewModel.onPlayAgainComplete()
   }
})

Импортируйте androidx.navigation.fragment.findNavController по запросу Android Studio.

  1. В ScoreFragment внутри onCreateView() добавьте прослушиватель щелчков для кнопки PlayAgain и вызовите viewModel .onPlayAgain() .
binding.playAgainButton.setOnClickListener {  viewModel.onPlayAgain()  }
  1. Запустите приложение и играйте. После завершения игры на экране счёта отобразится итоговый счёт и кнопка « Играть снова» . Нажмите кнопку «Играть снова» , и приложение перейдёт на экран игры, чтобы вы могли сыграть ещё раз.

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

Проект Android Studio: GuessTheWord

LiveData

  • LiveData — это класс хранилища наблюдаемых данных, учитывающий жизненный цикл, один из компонентов архитектуры Android .
  • Вы можете использовать LiveData , чтобы ваш пользовательский интерфейс автоматически обновлялся при обновлении данных.
  • LiveData является наблюдаемым, что означает, что наблюдатель, такой как активность или фрагмент, может быть уведомлен об изменении данных, хранящихся в объекте LiveData .
  • LiveData хранит данные; это оболочка, которую можно использовать с любыми данными.
  • LiveData учитывает жизненный цикл, то есть обновляет только наблюдателей, находящихся в активном состоянии жизненного цикла, например STARTED или RESUMED .

Чтобы добавить LiveData

  • Измените тип переменных данных в ViewModel на LiveData или MutableLiveData .

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

  • Чтобы изменить значение данных, хранящихся в LiveData , используйте метод setValue() для переменной LiveData .

Для инкапсуляции LiveData

  • LiveData внутри ViewModel должны быть доступны для редактирования. Вне ViewModel данные LiveData должны быть доступны для чтения. Это можно реализовать с помощью резервного свойства Kotlin.
  • Резервное свойство Kotlin позволяет вам возвращать из геттера что-то, отличное от самого объекта.
  • Чтобы инкапсулировать LiveData , используйте private MutableLiveData внутри ViewModel и верните резервное свойство LiveData за пределами ViewModel .

Наблюдаемые LiveData

  • LiveData следует шаблону наблюдателя. Наблюдаемым объектом является объект LiveData , а наблюдателями — методы в контроллерах пользовательского интерфейса, например, фрагменты. При каждом изменении данных, обёрнутых в LiveData , методы наблюдателя в контроллерах пользовательского интерфейса получают уведомление.
  • Чтобы сделать LiveData наблюдаемым, прикрепите объект наблюдателя к ссылке LiveData в наблюдателях (таких как действия и фрагменты) с помощью метода observe() .
  • Этот шаблон наблюдателя LiveData можно использовать для связи между ViewModel и контроллерами пользовательского интерфейса.

Курс Udacity:

Документация для разработчиков Android:

Другой:

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

  • При необходимости задавайте домашнее задание.
  • Объясните учащимся, как следует сдавать домашние задания.
  • Оцените домашние задания.

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

Если вы работаете с этой лабораторной работой самостоятельно, можете использовать эти домашние задания для проверки своих знаний.

Ответьте на эти вопросы

Вопрос 1

Как инкапсулировать LiveData хранящиеся в ViewModel , чтобы внешние объекты могли считывать данные, не имея возможности обновлять их?

  • Внутри объекта ViewModel измените тип данных на private LiveData . Используйте резервное свойство, чтобы предоставить данные типа MutableLiveData только для чтения.
  • Внутри объекта ViewModel измените тип данных на private MutableLiveData . Используйте резервное свойство, чтобы предоставить данные типа LiveData только для чтения.
  • Внутри контроллера пользовательского интерфейса измените тип данных на private MutableLiveData . Используйте резервное свойство, чтобы предоставить данные типа LiveData только для чтения.
  • Внутри объекта ViewModel измените тип данных на LiveData . Используйте резервное свойство, чтобы предоставить данные типа LiveData только для чтения.

Вопрос 2

LiveData обновляет контроллер пользовательского интерфейса (например, фрагмент), если контроллер пользовательского интерфейса находится в каком из следующих состояний?

  • Возобновлено
  • На заднем плане
  • Приостановлено
  • Остановлено

Вопрос 3

Что является наблюдаемым элементом (что наблюдается) в шаблоне наблюдателя LiveData ?

  • Метод наблюдателя
  • Данные в объекте LiveData
  • Контроллер пользовательского интерфейса
  • Объект ViewModel

Начните следующий урок: 5.3: Связывание данных с ViewModel и LiveData

Ссылки на другие практические занятия по этому курсу см. на целевой странице практических занятий по основам Android Kotlin .