Эта кодовая лаборатория является частью курса 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, созданное в предыдущей кодовой лаборатории, в качестве начального кода или скачать начальное приложение.
- (Необязательно) Если вы не используете код из предыдущей лаборатории кода, загрузите начальный код для этой лаборатории кода. Разархивируйте код и откройте проект в Android Studio.
- Запустите приложение и играйте.
- Обратите внимание, что кнопка « Пропустить » отображает следующее слово и уменьшает оценку на единицу, а кнопка « Понятно » показывает следующее слово и увеличивает оценку на единицу. Кнопка End Game завершает игру.
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
.
- В
GameViewModel
вonSkip()
измените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)
}
}
- В
GameFragment
внутриupdateWordText()
измените ссылку наviewModel
.word
наviewModel
.
word
.
value.
/** 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()
}
- В
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)
}
- Убедитесь, что в вашем коде нет ошибок. Скомпилируйте и запустите ваше приложение. Функциональность приложения должна быть такой же, как и раньше.
Эта задача тесно связана с предыдущей задачей, в которой вы преобразовывали партитуру и данные слов в объекты 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
должна редактировать данные в вашем приложении. Но контроллеры пользовательского интерфейса должны считывать данные, поэтому поля данных не могут быть полностью закрытыми. Чтобы инкапсулировать данные вашего приложения, вы используете объекты 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)
}
}
Отличная работа, вы инкапсулировали word
и score
объектов LiveData
.
Ваше текущее приложение переходит к экрану счета, когда пользователь нажимает кнопку « Завершить игру» . Вы также хотите, чтобы приложение переходило к экрану подсчета очков, когда игроки повторяли все слова. После того, как игроки произнесут последнее слово, вы хотите, чтобы игра завершалась автоматически, чтобы пользователю не приходилось нажимать кнопку.
Чтобы реализовать эту функциональность, вам нужно, чтобы событие было запущено и передано фрагменту из 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
, вызывается связанный метод наблюдателя во фрагменте игры, и приложение переходит к фрагменту экрана. - Код, который вы добавили, привел к проблеме жизненного цикла. Чтобы понять проблему, в классе
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)
}
- Запустите приложение, поиграйте в игру и просмотрите все слова. В нижней части игрового экрана ненадолго появляется всплывающее сообщение «Игра только что закончилась», что является ожидаемым поведением.
Теперь поверните устройство или эмулятор. Тост снова отображается! Поверните устройство еще несколько раз, и вы, вероятно, каждый раз будете видеть тост. Это ошибка, потому что тост должен отображаться только один раз, когда игра закончена. Тост не должен отображаться каждый раз при повторном создании фрагмента. Вы решите эту проблему в следующей задаче.
Шаг 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() }
- Запустите свое приложение и играйте в игру. Когда игра закончена, на экране счета отображается окончательный счет и кнопка « Играть снова» . Нажмите кнопку 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
Начать следующий урок:
Ссылки на другие лаборатории кода в этом курсе см. на целевой странице лаборатории кода Android Kotlin Fundamentals .