Android Kotlin Fundamentals 05.2: LiveData и наблюдатели LiveData

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

Введение

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

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

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

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

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

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

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

Экран игры

Экран счета

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

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

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. В GameViewModel в onSkip() измените 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. В GameFragment внутри updateWordText() измените ссылку на viewModel .word на viewModel . word . value.
/** 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. В GameFragment внутри gameFinished() измените ссылку на viewModel viewModel .score . score . value . Добавьте требуемую null проверку безопасности.
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 должна редактировать данные в вашем приложении. Но контроллеры пользовательского интерфейса должны считывать данные, поэтому поля данных не могут быть полностью закрытыми. Чтобы инкапсулировать данные вашего приложения, вы используете объекты 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)
   }
}

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

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

Чтобы реализовать эту функциональность, вам нужно, чтобы событие было запущено и передано фрагменту из 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. Код, который вы добавили, привел к проблеме жизненного цикла. Чтобы понять проблему, в классе GameFragment закомментируйте код навигации в gameFinished() . Не забудьте сохранить сообщение 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. Запустите свое приложение и играйте в игру. Когда игра закончена, на экране счета отображается окончательный счет и кнопка « Играть снова» . Нажмите кнопку PlayAgain , и приложение перейдет к экрану игры, чтобы вы могли снова сыграть в игру.

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

Проект Android Studio: GuessTheWord

LiveData

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

Чтобы добавить Live Data

  • Измените тип переменных данных в 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 и контроллерами пользовательского интерфейса.

Удасити курс:

Документация для разработчиков 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 Fundamentals .