Эта практическая работа входит в курс «Основы 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, созданное в предыдущей лабораторной работе, или скачать готовое стартовое приложение.
- (Необязательно) Если вы не используете код из предыдущей лабораторной работы, скачайте начальный код для этой. Распакуйте код и откройте проект в Android Studio.
- Запустите приложение и играйте в игру.
- Обратите внимание, что кнопка «Пропустить» отображает следующее слово и уменьшает счёт на один, а кнопка « Понял» отображает следующее слово и увеличивает счёт на один. Кнопка «Завершить игру» завершает игру.
LiveData
— это класс-хранилище наблюдаемых данных, учитывающий жизненный цикл. Например, вы можете обернуть LiveData
вокруг текущего счёта в приложении GuessTheWord. В этой практической работе вы узнаете о нескольких характеристиках LiveData
:
-
LiveData
является наблюдаемым, что означает, что наблюдатель уведомляется об изменении данных, хранящихся в объектеLiveData
. -
LiveData
хранит данные;LiveData
— это оболочка, которую можно использовать с любыми данными. -
LiveData
учитывает жизненный цикл, то есть обновляет только наблюдателей, находящихся в активном состоянии жизненного цикла, напримерSTARTED
илиRESUMED
.
В этом задании вы научитесь обертывать любые типы данных в объекты LiveData
, преобразуя текущие данные о счёте и слове в GameViewModel
в LiveData
. В следующем задании вы добавите наблюдателя к этим объектам LiveData
и научитесь наблюдать LiveData
.
Шаг 1: Измените счет и слово, чтобы использовать LiveData
- В пакете
screens/game
откройте файлGameViewModel
. - Измените тип переменных
score
иword
наMutableLiveData
.
MutableLiveData
— это классLiveData
, значение которого можно изменять.MutableLiveData
— это универсальный класс, поэтому необходимо указать тип хранимых им данных.
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()
- В
GameViewModel
, внутри блокаinit
, инициализируйтеscore
иword
. Чтобы изменить значение переменнойLiveData
, используйте методsetValue()
. В Kotlin методsetValue()
можно вызвать, используя свойствоvalue
.
init {
word.value = ""
score.value = 0
...
}
Шаг 2: Обновите ссылку на объект LiveData
Переменные score
и word
теперь имеют тип LiveData
. На этом этапе вы изменяете ссылки на эти переменные, используя свойство value
.
- В методе
onSkip()
вGameViewModel
изменитеscore
наscore.value
. Обратите внимание на ошибку о возможномscore
вnull
. Эту ошибку нужно исправить следующим способом. - Чтобы устранить ошибку, добавьте проверку
null
вscore.value
вonSkip()
. Затем вызовите функциюminus()
дляscore
, которая выполнит вычитание с защитойnull
.
fun onSkip() {
if (!wordList.isEmpty()) {
score.value = (score.value)?.minus(1)
}
nextWord()
}
- Обновите метод
onCorrect()
таким же образом: добавьте проверкуnull
к переменнойscore
и используйте функциюplus()
.
fun onCorrect() {
if (!wordList.isEmpty()) {
score.value = (score.value)?.plus(1)
}
nextWord()
}
- В
GameViewModel
внутри методаnextWord()
измените ссылкуword
наword
.
value
.
private fun nextWord() {
if (!wordList.isEmpty()) {
//Select and remove a word from the list
word.value = wordList.removeAt(0)
}
}
-
value.
GameFragment
внутри методаupdateWordText()
.
.
viewModel
word
viewModel
.word
/** Methods for updating the UI **/
private fun updateWordText() {
binding.wordText.text = viewModel.word.value
}
- В
GameFragment
, внутри методаupdateScoreText()
, измените ссылку.
viewModel
.score
наviewModel
.
score
value.
private fun updateScoreText() {
binding.scoreText.text = viewModel.score.value.toString()
}
- В методе
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)
}
- Убедитесь, что в вашем коде нет ошибок. Скомпилируйте и запустите приложение. Функциональность приложения должна остаться прежней.
Эта задача тесно связана с предыдущей, где вы преобразовали данные о счёте и словах в объекты LiveData
. В этой задаче вы прикрепляете объекты Observer
к этим объектам LiveData
.
- В методе
GameFragment,
onCreateView()
присоедините объектObserver
к объектуLiveData
для текущего счётаviewModel.score
. Используйте методobserve()
и поместите код после инициализацииviewModel
. Для упрощения кода используйте лямбда-выражение. ( Лямбда-выражение — это анонимная функция, которая не объявляется, а передаётся непосредственно как выражение.)
viewModel.score.observe(this, Observer { newScore ->
})
Разрешите ссылку на Observer
. Для этого выберите Observer
, нажмите Alt+Enter
( Option+Enter
на Mac) и импортируйте androidx.lifecycle.Observer
.
- Наблюдатель, который вы только что создали, получает событие при изменении данных, хранящихся в наблюдаемом объекте
LiveData
. Внутри наблюдателя обновитеTextView
счёта, указав новый счёт.
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
- Прикрепите объект
Observer
к текущему объектуLiveData
слова. Сделайте это так же, как вы прикрепили объектObserver
к текущему счёту.
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
binding.wordText.text = newWord
})
При изменении значения score
или word
score
или word
, отображаемые на экране, теперь обновляются автоматически.
- В
GameFragment
удалите методыupdateWordText()
иupdateScoreText()
и все ссылки на них. Они вам больше не понадобятся, поскольку текстовые представления обновляются методами наблюдателяLiveData
. - Запустите приложение. Ваше игровое приложение должно работать точно так же, как и раньше, но теперь оно использует
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.
Добавить свойство поддержки к партитуре и слову
- В
GameViewModel
сделайте текущий объектscore
private
. - Чтобы следовать соглашению об именовании, используемому в резервных свойствах, измените
score
на_score
. Свойство_score
теперь представляет собой изменяемую версию игрового счёта для внутреннего использования. - Создайте публичную версию типа
LiveData
под названиемscore
.
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
- Вы видите ошибку инициализации. Эта ошибка возникает, потому что внутри
GameFragment
score
является ссылкойLiveData
, иscore
больше не может получить доступ к своему сеттеру. Подробнее о геттерах и сеттерах в Kotlin см. в разделе Геттеры и сеттеры .
Чтобы устранить ошибку, переопределите методget()
для объектаscore
вGameViewModel
и верните резервное свойство_score
.
val score: LiveData<Int>
get() = _score
- В
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)
}
...
}
- Переименуйте объект
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
для моделирования события завершения игры.
- В
GameViewModel
создайте объектBoolean
MutableLiveData
с именем_eventGameFinish
. Этот объект будет хранить событие завершения игры. - После инициализации объекта
_eventGameFinish
создайте и инициализируйте резервное свойство с именемeventGameFinish
.
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
get() = _eventGameFinish
- В
GameViewModel
добавьте методonGameFinish()
. В этом методе установите для события завершения игрыeventGameFinish
значениеtrue
.
/** Method for the game completed event **/
fun onGameFinish() {
_eventGameFinish.value = true
}
- В
GameViewModel
внутри методаnextWord()
завершите игру, если список слов пуст.
private fun nextWord() {
if (wordList.isEmpty()) {
onGameFinish()
} else {
//Select and remove a _word from the list
_word.value = wordList.removeAt(0)
}
}
- В
GameFragment
, внутриonCreateView()
, после инициализацииviewModel
, присоедините наблюдателя кeventGameFinish
. Используйте методobserve()
. Внутри лямбда-функции вызовите методgameFinished()
.
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
if (hasFinished) gameFinished()
})
- Запустите приложение, сыграйте в игру и пройдите все слова. Приложение автоматически перейдет к экрану счёта, а не останется в игровом фрагменте, пока вы не нажмёте «Завершить игру» .
После того, как список слов опустеет, устанавливаетсяeventGameFinish
, вызывается связанный метод наблюдателя в игровом фрагменте, и приложение переходит к фрагменту экрана. - Добавленный вами код создал проблему жизненного цикла. Чтобы разобраться в проблеме, закомментируйте код навигации в методе
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)
}
- Запустите приложение, играйте и пройдитесь по всем словам. В нижней части игрового экрана на короткое время появится всплывающее сообщение «Игра только что завершена», что вполне ожидаемо.
Теперь поверните устройство или эмулятор. Уведомление снова появится! Поверните устройство ещё несколько раз, и, вероятно, вы будете видеть уведомление каждый раз. Это ошибка, поскольку уведомление должно появляться только один раз, после завершения игры. Уведомление не должно появляться каждый раз при пересоздании фрагмента. Вы решите эту проблему в следующем задании.
Шаг 2: Сброс события завершения игры
Обычно LiveData
отправляет обновления наблюдателям только при изменении данных. Исключением из этого правила является то, что наблюдатели также получают обновления при переходе из неактивного состояния в активное.
Именно поэтому уведомление о завершении игры постоянно запускается в вашем приложении. Когда фрагмент игры пересоздаётся после поворота экрана, он переходит из неактивного состояния в активное. Наблюдатель во фрагменте повторно подключается к существующей ViewModel
и получает текущие данные. Метод gameFinished()
запускается повторно, и уведомление отображается.
В этой задаче вы исправите эту проблему и отобразите уведомление только один раз, сбросив флаг eventGameFinish
в GameViewModel
.
- В
GameViewModel
добавьте методonGameFinishComplete()
для сброса события завершения игры,_eventGameFinish
.
/** Method for the game completed event **/
fun onGameFinishComplete() {
_eventGameFinish.value = false
}
- В
GameFragment
, в концеgameFinished()
, вызовитеonGameFinishComplete()
для объектаviewModel
. (Пока оставьте код навигации вgameFinished()
закомментированным.)
private fun gameFinished() {
...
viewModel.onGameFinishComplete()
}
- Запустите приложение и играйте. Прочитайте все слова, а затем измените ориентацию экрана устройства. Уведомление отображается только один раз.
- В
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
.
- Запустите приложение и играйте. Убедитесь, что приложение автоматически перейдёт на экран с итоговым счётом после того, как вы разгадаете все слова.
Отличная работа! Ваше приложение использует LiveData
для активации события завершения игры, чтобы сообщить GameViewModel
фрагменту игры о том, что список слов пуст. Затем фрагмент игры переходит к фрагменту счёта.
В этой задаче вы преобразуете счёт в объект LiveData
в ScoreViewModel
и присоединяете к нему наблюдателя. Эта задача аналогична той, что вы выполняли при добавлении LiveData
в GameViewModel
.
Эти изменения вносятся в ScoreViewModel
для полноты картины, чтобы все данные в вашем приложении использовали LiveData
.
- В
ScoreViewModel
измените тип переменнойscore
наMutableLiveData
. Переименуйте её по соглашению в_score
и добавьте резервное свойство.
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
get() = _score
- В
ScoreViewModel
, внутри блокаinit
, инициализируйте_score
. Вы можете удалить или оставить журнал в блокеinit
по своему усмотрению.
init {
_score.value = finalScore
}
- В
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
.
- Запустите приложение и играйте. Приложение должно работать как и прежде, но теперь оно использует
LiveData
и наблюдателя для обновления счёта.
В этой задаче вы добавите кнопку «Играть снова» на экран счёта и реализуете её прослушиватель кликов с помощью события LiveData
. Кнопка запускает событие для перехода с экрана счёта на экран игры.
Стартовый код приложения включает кнопку «Воспроизвести снова» , но она скрыта.
- В
res/layout/score_fragment.xml
для кнопкиplay_again_button
измените значение атрибутаvisibility
наvisible
.
<Button
android:id="@+id/play_again_button"
...
android:visibility="visible"
/>
- В
ScoreViewModel
добавьте объектLiveData
для храненияBoolean
_eventPlayAgain
. Этот объект используется для сохранения событияLiveData
для перехода с экрана счёта на экран игры.
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
get() = _eventPlayAgain
- В
ScoreViewModel
определите методы для установки и сброса события_eventPlayAgain
.
fun onPlayAgain() {
_eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
_eventPlayAgain.value = false
}
- В
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.
- В
ScoreFragment
внутриonCreateView()
добавьте прослушиватель щелчков для кнопки PlayAgain и вызовитеviewModel
.onPlayAgain()
.
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }
- Запустите приложение и играйте. После завершения игры на экране счёта отобразится итоговый счёт и кнопка « Играть снова» . Нажмите кнопку «Играть снова» , и приложение перейдёт на экран игры, чтобы вы могли сыграть ещё раз.
Отличная работа! Вы изменили архитектуру своего приложения для использования объектов 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:
Другой:
- Поддержка собственности в Kotlin
В этом разделе перечислены возможные домашние задания для студентов, работающих над этой лабораторной работой в рамках курса, проводимого преподавателем. Преподаватель должен выполнить следующие действия:
- При необходимости задавайте домашнее задание.
- Объясните учащимся, как следует сдавать домашние задания.
- Оцените домашние задания.
Преподаватели могут использовать эти предложения так часто или редко, как пожелают, и могут свободно задавать любые другие домашние задания, которые они сочтут подходящими.
Если вы работаете с этой лабораторной работой самостоятельно, можете использовать эти домашние задания для проверки своих знаний.
Ответьте на эти вопросы
Вопрос 1
Как инкапсулировать LiveData
хранящиеся в ViewModel
, чтобы внешние объекты могли считывать данные, не имея возможности обновлять их?
- Внутри объекта
ViewModel
измените тип данных наprivate
LiveData
. Используйте резервное свойство, чтобы предоставить данные типаMutableLiveData
только для чтения. - Внутри объекта
ViewModel
измените тип данных наprivate
MutableLiveData
. Используйте резервное свойство, чтобы предоставить данные типаLiveData
только для чтения. - Внутри контроллера пользовательского интерфейса измените тип данных на
private
MutableLiveData
. Используйте резервное свойство, чтобы предоставить данные типаLiveData
только для чтения. - Внутри объекта
ViewModel
измените тип данных наLiveData
. Используйте резервное свойство, чтобы предоставить данные типаLiveData
только для чтения.
Вопрос 2
LiveData
обновляет контроллер пользовательского интерфейса (например, фрагмент), если контроллер пользовательского интерфейса находится в каком из следующих состояний?
- Возобновлено
- На заднем плане
- Приостановлено
- Остановлено
Вопрос 3
Что является наблюдаемым элементом (что наблюдается) в шаблоне наблюдателя LiveData
?
- Метод наблюдателя
- Данные в объекте
LiveData
- Контроллер пользовательского интерфейса
- Объект
ViewModel
Начните следующий урок:
Ссылки на другие практические занятия по этому курсу см. на целевой странице практических занятий по основам Android Kotlin .