Dieses Codelab ist Teil des Kurses „Grundlagen von Android und Kotlin“. Sie können diesen Kurs am besten nutzen, wenn Sie die Codelabs der Reihe nach durcharbeiten. Alle Codelabs des Kurses sind auf der Landingpage für Codelabs zu den Grundlagen von Android und Kotlin aufgeführt.
Einführung
Im vorherigen Codelab haben Sie in der App „GuessTheWord“ ein ViewModel verwendet, damit die Daten der App Änderungen an der Gerätekonfiguration überstehen. In diesem Codelab erfahren Sie, wie Sie LiveData in die Daten der ViewModel-Klassen einbinden. Mit LiveData, einer der Android Architecture Components, können Sie Datenobjekte erstellen, die Ansichten benachrichtigen, wenn sich die zugrunde liegende Datenbank ändert.
Um die Klasse LiveData zu verwenden, richten Sie „Beobachter“ (z. B. Aktivitäten oder Fragmente) ein, die Änderungen an den Daten der App beobachten. LiveData ist lebenszyklusbezogen. Daher werden nur App-Komponenten-Beobachter aktualisiert, die sich in einem aktiven Lebenszyklusstatus befinden.
Was Sie bereits wissen sollten
- So erstellen Sie grundlegende Android-Apps in Kotlin.
- So navigieren Sie zwischen den Zielen Ihrer App.
- Aktivitäts- und Fragmentlebenszyklus.
ViewModel-Objekte in Ihrer App verwendenViewModel-Objekte mit derViewModelProvider.Factory-Schnittstelle erstellen
Lerninhalte
- Was
LiveData-Objekte nützlich macht. - So fügen Sie
LiveDatazu den in einerViewModelgespeicherten Daten hinzu. - Wann und wie Sie
MutableLiveDataverwenden. - Beobachtermethoden hinzufügen, um Änderungen in
LiveData.zu beobachten LiveDatamit einer Backing Property kapseln- So kommunizieren Sie zwischen einem UI-Controller und dem entsprechenden
ViewModel.
Aufgaben
- Verwende
LiveDatafür das Wort und die Punktzahl in der GuessTheWord App. - Fügen Sie Beobachter hinzu, die bemerken, wenn sich das Wort oder die Punktzahl ändert.
- Aktualisieren Sie die Textansichten, in denen geänderte Werte angezeigt werden.
- Verwende das
LiveData-Beobachtermuster, um ein Ereignis für das Ende eines Spiels hinzuzufügen. - Implementieren Sie die Schaltfläche Nochmal spielen.
In den Codelabs zu Lektion 5 entwickeln Sie die App „GuessTheWord“ auf Grundlage von Startcode. GuessTheWord ist ein Schattenspiel für zwei Spieler, bei dem die Spieler zusammenarbeiten, um die höchstmögliche Punktzahl zu erreichen.
Der erste Spieler sieht sich die Wörter in der App an und stellt sie nacheinander dar, ohne dem zweiten Spieler das Wort zu zeigen. Der zweite Spieler versucht, das Wort zu erraten.
Um das Spiel zu starten, öffnet der erste Spieler die App auf dem Gerät und sieht ein Wort, z. B. „Gitarre“, wie im Screenshot unten zu sehen.
Der erste Spieler stellt das Wort dar, ohne es auszusprechen.
- Wenn der zweite Spieler das Wort richtig errät, drückt der erste Spieler auf die Schaltfläche Got It (Erraten). Dadurch wird die Anzahl um eins erhöht und das nächste Wort angezeigt.
- Wenn der zweite Spieler das Wort nicht erraten kann, drückt der erste Spieler die Schaltfläche Überspringen. Dadurch wird die Anzahl um eins verringert und zum nächsten Wort gesprungen.
- Drücken Sie die Schaltfläche Spiel beenden, um das Spiel zu beenden. (Diese Funktion ist nicht im Startercode für das erste Codelab der Reihe enthalten.)
In diesem Codelab verbessern Sie die App „GuessTheWord“, indem Sie ein Ereignis hinzufügen, um das Spiel zu beenden, wenn der Nutzer alle Wörter in der App durchlaufen hat. Außerdem fügen Sie dem Score-Fragment die Schaltfläche Play Again (Nochmal spielen) hinzu, damit der Nutzer das Spiel noch einmal spielen kann.
Titelbildschirm |
Spielbildschirm |
Bewertungsbildschirm |
In dieser Aufgabe suchen Sie den Startcode für dieses Codelab und führen ihn aus. Sie können die GuessTheWord-App, die Sie im vorherigen Codelab erstellt haben, als Startcode verwenden oder eine Starter-App herunterladen.
- (Optional) Wenn Sie den Code aus dem vorherigen Codelab nicht verwenden, laden Sie den Startcode für dieses Codelab herunter. Entpacken Sie den Code und öffnen Sie das Projekt in Android Studio.
- Führen Sie die App aus und spielen Sie das Spiel.
- Die Schaltfläche Überspringen zeigt das nächste Wort an und verringert die Punktzahl um eins. Die Schaltfläche Verstanden zeigt das nächste Wort an und erhöht die Punktzahl um eins. Mit der Schaltfläche Spiel beenden wird das Spiel beendet.
LiveData ist eine beobachtbare Datenhalterklasse, die den Lebenszyklus berücksichtigt. Sie können beispielsweise ein LiveData um die aktuelle Punktzahl in der App „GuessTheWord“ legen. In diesem Codelab erfahren Sie mehr über verschiedene Eigenschaften von LiveData:
LiveDataist beobachtbar. Das bedeutet, dass ein Beobachter benachrichtigt wird, wenn sich die Daten desLiveData-Objekts ändern.LiveDataenthält Daten;LiveDataist ein Wrapper, der mit beliebigen Daten verwendet werden kann.LiveDataist lebenszyklusbezogen. Das bedeutet, dass nur Beobachter aktualisiert werden, die sich in einem aktiven Lebenszyklusstatus wieSTARTEDoderRESUMEDbefinden.
In dieser Aufgabe erfahren Sie, wie Sie einen beliebigen Datentyp in LiveData-Objekte einfügen, indem Sie die aktuellen Punkt- und Wortdaten in GameViewModel in LiveData konvertieren. In einer späteren Aufgabe fügen Sie diesen LiveData-Objekten einen Observer hinzu und erfahren, wie Sie die LiveData beobachten.
Schritt 1: Den Score und das Wort ändern, um LiveData zu verwenden
- Öffnen Sie im Paket
screens/gamedie DateiGameViewModel. - Ändern Sie den Typ der Variablen
scoreundwordinMutableLiveData.MutableLiveDataist eineLiveData, deren Wert geändert werden kann.MutableLiveDataist eine generische Klasse. Sie müssen also den Datentyp angeben, den sie enthält.
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()- Initialisieren Sie in
GameViewModelim Blockinitdie Variablenscoreundword. Wenn Sie den Wert einerLiveData-Variablen ändern möchten, verwenden Sie die MethodesetValue()für die Variable. In Kotlin können SiesetValue()mit der Propertyvalueaufrufen.
init {
word.value = ""
score.value = 0
...
}Schritt 2: LiveData-Objektreferenz aktualisieren
Die Variablen score und word sind jetzt vom Typ LiveData. In diesem Schritt ändern Sie die Verweise auf diese Variablen mithilfe der Eigenschaft value.
- Ändern Sie in
GameViewModelin der MethodeonSkip()scoreinscore.value. Beachten Sie den Fehler, dassscoremöglicherweisenullist. Sie beheben diesen Fehler als Nächstes. - Fügen Sie in
onSkip()einennull-Check zuscore.valuehinzu, um den Fehler zu beheben. Rufen Sie dann die Funktionminus()fürscoreauf, um die Subtraktion mitnull-Sicherheit auszuführen.
fun onSkip() {
if (!wordList.isEmpty()) {
score.value = (score.value)?.minus(1)
}
nextWord()
}- Aktualisieren Sie die Methode
onCorrect()auf dieselbe Weise: Fügen Sie der Variablenscoreeinenull-Prüfung hinzu und verwenden Sie die Funktionplus().
fun onCorrect() {
if (!wordList.isEmpty()) {
score.value = (score.value)?.plus(1)
}
nextWord()
}- Ändern Sie in
GameViewModelin der MethodenextWord()den Verweiswordinword.value.
private fun nextWord() {
if (!wordList.isEmpty()) {
//Select and remove a word from the list
word.value = wordList.removeAt(0)
}
}- Ändern Sie in
GameFragmentin der MethodeupdateWordText()den Verweis aufviewModel.wordinviewModel.word.value..
/** Methods for updating the UI **/
private fun updateWordText() {
binding.wordText.text = viewModel.word.value
}- Ändern Sie in
GameFragmentin der MethodeupdateScoreText()den Verweis aufviewModel.scoreinviewModel.score.value..
private fun updateScoreText() {
binding.scoreText.text = viewModel.score.value.toString()
}- Ändern Sie in
GameFragmentin der MethodegameFinished()den Verweis aufviewModel.scoreinviewModel.score.value. Fügen Sie den erforderlichennull-Sicherheitscheck hinzu.
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)
}- Achten Sie darauf, dass Ihr Code keine Fehler enthält. Kompilieren und führen Sie Ihre App aus. Die Funktionalität der App sollte dieselbe sein wie zuvor.
Diese Aufgabe hängt eng mit der vorherigen Aufgabe zusammen, in der Sie die Punktzahl- und Wortdaten in LiveData-Objekte konvertiert haben. In dieser Aufgabe hängen Sie Observer-Objekte an diese LiveData-Objekte an.
- Hängen Sie in
GameFragment,in der MethodeonCreateView()einObserver-Objekt an dasLiveData-Objekt für die aktuelle Punktzahl,viewModel.score, an. Verwenden Sie die Methodeobserve()und fügen Sie den Code nach der Initialisierung vonviewModelein. Verwenden Sie einen Lambda-Ausdruck, um den Code zu vereinfachen. Ein Lambda-Ausdruck ist eine anonyme Funktion, die nicht deklariert, sondern sofort als Ausdruck übergeben wird.
viewModel.score.observe(this, Observer { newScore ->
})Lösen Sie den Verweis auf Observer auf. Klicken Sie dazu auf Observer, drücken Sie Alt+Enter (Option+Enter auf einem Mac) und importieren Sie androidx.lifecycle.Observer.
- Der gerade erstellte Observer empfängt ein Ereignis, wenn sich die Daten des beobachteten
LiveData-Objekts ändern. Aktualisieren Sie im Observer den Wert fürTextViewmit dem neuen Wert.
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})- Hängen Sie ein
Observer-Objekt an das aktuelleLiveData-Objekt an. Gehen Sie dabei genauso vor wie beim Anhängen einesObserver-Objekts an den aktuellen Score.
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
binding.wordText.text = newWord
})Wenn sich der Wert von score oder word ändert, wird der auf dem Bildschirm angezeigte Wert von score oder word jetzt automatisch aktualisiert.
- Löschen Sie in
GameFragmentdie MethodenupdateWordText()undupdateScoreText()sowie alle Verweise darauf. Sie werden nicht mehr benötigt, da die Textansichten durch dieLiveData-Beobachtermethoden aktualisiert werden. - Führen Sie Ihre App aus. Ihre Spiele-App sollte genau wie zuvor funktionieren, verwendet jetzt aber
LiveDataundLiveData-Beobachter.
Kapselung ist eine Möglichkeit, den direkten Zugriff auf einige Felder eines Objekts einzuschränken. Wenn Sie ein Objekt kapseln, stellen Sie eine Reihe öffentlicher Methoden bereit, mit denen die privaten internen Felder geändert werden können. Durch die Kapselung steuern Sie, wie andere Klassen diese internen Felder bearbeiten.
In Ihrem aktuellen Code kann jede externe Klasse die Variablen score und word mit der Eigenschaft value ändern, z. B. mit viewModel.score.value. In der App, die Sie in diesem Codelab entwickeln, spielt das möglicherweise keine Rolle. In einer Produktions-App sollten Sie jedoch die Daten in den ViewModel-Objekten kontrollieren.
Nur die ViewModel sollte die Daten in Ihrer App bearbeiten. UI-Controller müssen die Daten jedoch lesen können, daher können die Datenfelder nicht vollständig privat sein. Zum Kapseln der Daten Ihrer App verwenden Sie sowohl MutableLiveData- als auch LiveData-Objekte.
MutableLiveData im Vergleich zu LiveData:
- Daten in einem
MutableLiveData-Objekt können geändert werden, wie der Name schon sagt. Innerhalb vonViewModelsollten die Daten bearbeitbar sein. Daher wirdMutableLiveDataverwendet. - Daten in einem
LiveData-Objekt können gelesen, aber nicht geändert werden. Außerhalb vonViewModelsollten Daten lesbar, aber nicht bearbeitbar sein. Daher sollten die Daten alsLiveDataverfügbar gemacht werden.
Für diese Strategie verwenden Sie eine Backing Property in Kotlin. Mit einer Backing Property können Sie etwas anderes als das genaue Objekt aus einem Getter zurückgeben. In dieser Aufgabe implementieren Sie eine Sicherungseigenschaft für die Objekte score und word in der App „GuessTheWord“.
Dem Ergebnis und dem Wort eine unterstützende Property hinzufügen
- Machen Sie in
GameViewModeldas aktuellescore-Objekt zuprivate. - Wenn Sie die in den zugrunde liegenden Attributen verwendete Namenskonvention verwenden möchten, ändern Sie
scorein_score. Die Property_scoreist jetzt die veränderbare Version der Spielpunktzahl, die intern verwendet werden soll. - Erstellen Sie eine öffentliche Version des Typs
LiveDatamit dem Namenscore.
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>- Es wird ein Initialisierungsfehler angezeigt. Dieser Fehler tritt auf, weil
scoreinGameFragmenteinLiveData-Verweis ist undscorenicht mehr auf seinen Setter zugreifen kann. Weitere Informationen zu Gettern und Settern in Kotlin finden Sie unter Getter und Setter.
Um den Fehler zu beheben, überschreiben Sie die Methodeget()für dasscore-Objekt inGameViewModelund geben Sie die Sicherungseigenschaft_scorezurück.
val score: LiveData<Int>
get() = _score- Ändern Sie im
GameViewModeldie Verweise vonscorein die interne veränderliche Version_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)
}
...
}- Benennen Sie das
word-Objekt in_wordum und fügen Sie eine Backing-Property dafür hinzu, wie Sie es für dasscore-Objekt getan haben.
// 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)
}
}Gut gemacht! Sie haben die LiveData-Objekte word und score gekapselt.
In Ihrer aktuellen App wird der Nutzer zum Bildschirm mit dem Ergebnis weitergeleitet, wenn er auf die Schaltfläche Spiel beenden tippt. Außerdem soll die App zum Bildschirm mit der Punktzahl wechseln, wenn die Spieler alle Wörter durchlaufen haben. Nachdem die Spieler das letzte Wort eingegeben haben, soll das Spiel automatisch beendet werden, damit der Nutzer nicht auf die Schaltfläche tippen muss.
Um diese Funktion zu implementieren, muss ein Ereignis ausgelöst und an das Fragment von ViewModel gesendet werden, wenn alle Wörter angezeigt wurden. Dazu verwenden Sie das LiveData-Beobachtermuster, um ein Ereignis für das Ende des Spiels zu modellieren.
Das Observer-Muster
Das Beobachtermuster ist ein Software-Designmuster. Es wird die Kommunikation zwischen Objekten festgelegt: einem Observable (dem „Subjekt“ der Beobachtung) und Observers. Ein Observable ist ein Objekt, das Beobachter über Änderungen in seinem Status informiert.

Im Fall von LiveData in dieser App ist das Observable (Subjekt) das LiveData-Objekt und die Beobachter sind die Methoden in den UI-Controllern, z. B. Fragmente. Eine Statusänderung erfolgt immer dann, wenn sich die in LiveData enthaltenen Daten ändern. Die LiveData-Klassen sind entscheidend für die Kommunikation vom ViewModel zum Fragment.
Schritt 1: LiveData verwenden, um ein Ereignis für das Ende eines Spiels zu erkennen
In dieser Aufgabe verwenden Sie das LiveData-Beobachtermuster, um ein Ereignis zu modellieren, das ausgelöst wird, wenn ein Spiel beendet ist.
- Erstellen Sie in
GameViewModeleinBoolean-MutableLiveData-Objekt mit dem Namen_eventGameFinish. Dieses Objekt enthält das Ereignis „Spiel beendet“. - Erstellen und initialisieren Sie nach der Initialisierung des
_eventGameFinish-Objekts eine Sicherungsproperty namenseventGameFinish.
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
get() = _eventGameFinish- Fügen Sie in
GameViewModeleineonGameFinish()-Methode hinzu. Legen Sie in der Methode das Ereignis „Spiel beendet“ (eventGameFinish) auftruefest.
/** Method for the game completed event **/
fun onGameFinish() {
_eventGameFinish.value = true
}- Beende das Spiel in
GameViewModelin der MethodenextWord(), wenn die Wortliste leer ist.
private fun nextWord() {
if (wordList.isEmpty()) {
onGameFinish()
} else {
//Select and remove a _word from the list
_word.value = wordList.removeAt(0)
}
}- Hängen Sie in
GameFragmentinnerhalb vononCreateView()nach der Initialisierung vonviewModeleinen Observer aneventGameFinishan. Verwenden Sie die Methodeobserve(). Rufen Sie in der Lambda-Funktion die MethodegameFinished()auf.
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
if (hasFinished) gameFinished()
})- Führen Sie Ihre App aus, spielen Sie das Spiel und gehen Sie alle Wörter durch. Die App wechselt automatisch zum Bildschirm mit dem Ergebnis, anstatt im Spiel-Fragment zu bleiben, bis Sie auf Spiel beenden tippen.
Wenn die Wortliste leer ist, wirdeventGameFinishfestgelegt, die zugehörige Beobachtermethode im Game-Fragment wird aufgerufen und die App wechselt zum Bildschirm-Fragment. - Der von Ihnen hinzugefügte Code hat ein Problem mit dem Lebenszyklus verursacht. Um das Problem zu verstehen, kommentieren Sie in der Klasse
GameFragmentden Navigationscode in der MethodegameFinished()aus. Achten Sie darauf, dieToast-Nachricht in der Methode beizubehalten.
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)
}
- Führen Sie Ihre App aus, spielen Sie das Spiel und gehen Sie alle Wörter durch. Unten auf dem Spielbildschirm wird kurz die Toast-Meldung „Das Spiel ist gerade beendet“ angezeigt. Das ist das erwartete Verhalten.
Drehen Sie das Gerät oder den Emulator. Der Hinweis wird wieder angezeigt. Drehen Sie das Gerät noch einige Male. Wahrscheinlich wird der Toast jedes Mal angezeigt. Das ist ein Fehler, da der Hinweis nur einmal angezeigt werden sollte, wenn das Spiel beendet ist. Der Toast sollte nicht jedes Mal angezeigt werden, wenn das Fragment neu erstellt wird. Sie beheben dieses Problem in der nächsten Aufgabe.
|
|
Schritt 2: Ereignis „Spiel beendet“ zurücksetzen
Normalerweise werden Aktualisierungen nur dann an die Beobachter gesendet, wenn sich Daten ändern.LiveData Eine Ausnahme von diesem Verhalten besteht darin, dass Beobachter auch dann Updates erhalten, wenn sich der Beobachter von einem inaktiven in einen aktiven Status ändert.
Aus diesem Grund wird der Toast „Spiel beendet“ in Ihrer App wiederholt ausgelöst. Wenn das Game-Fragment nach einer Bildschirmdrehung neu erstellt wird, wechselt es von einem inaktiven in einen aktiven Zustand. Der Observer im Fragment wird wieder mit dem vorhandenen ViewModel verbunden und empfängt die aktuellen Daten. Die Methode gameFinished() wird noch einmal ausgelöst und der Toast wird angezeigt.
In dieser Aufgabe beheben Sie dieses Problem und lassen den Toast nur einmal anzeigen, indem Sie das Flag eventGameFinish in GameViewModel zurücksetzen.
- Fügen Sie in
GameViewModeleineonGameFinishComplete()-Methode zum Zurücksetzen des Ereignisses „Spiel beendet“ (_eventGameFinish) hinzu.
/** Method for the game completed event **/
fun onGameFinishComplete() {
_eventGameFinish.value = false
}- Rufen Sie in
GameFragmentam Ende vongameFinished()onGameFinishComplete()für dasviewModel-Objekt auf. Lassen Sie den Navigationscode ingameFinished()vorerst auskommentiert.
private fun gameFinished() {
...
viewModel.onGameFinishComplete()
}- Führen Sie die App aus und spielen Sie das Spiel. Gehen Sie alle Wörter durch und ändern Sie dann die Bildschirmausrichtung des Geräts. Der Hinweis wird nur einmal angezeigt.
- Entfernen Sie in
GameFragmentinnerhalb der MethodegameFinished()die Auskommentierung des Navigationscodes.
Wählen Sie in Android Studio die auskommentierten Zeilen aus und drücken SieControl+/(Command+/auf einem Mac), um die Auskommentierung zu entfernen.
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()
}Wenn Sie von Android Studio dazu aufgefordert werden, importieren Sie androidx.navigation.fragment.NavHostFragment.findNavController.
- Führen Sie die App aus und spielen Sie das Spiel. Die App muss nach dem Durchgehen aller Wörter automatisch zum Bildschirm mit dem Endergebnis wechseln.
|
|
Gut gemacht! Ihre App verwendet LiveData, um ein Ereignis zum Spielende auszulösen und dem Spiel-Fragment mitzuteilen, dass die Wortliste leer ist.GameViewModel Das Spielfragment wechselt dann zum Ergebnisfragment.
In dieser Aufgabe ändern Sie den Wert in ein LiveData-Objekt in ScoreViewModel und hängen einen Observer daran an. Diese Aufgabe ähnelt der, die Sie beim Hinzufügen von LiveData zur GameViewModel ausgeführt haben.
Sie nehmen diese Änderungen an ScoreViewModel vor, damit alle Daten in Ihrer App LiveData verwenden.
- Ändern Sie in
ScoreViewModelden VariablentypscoreinMutableLiveData. Benennen Sie sie gemäß der Konvention in_scoreum und fügen Sie ein Backing-Attribut hinzu.
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
get() = _score- Initialisieren Sie
_scoreinScoreViewModelinnerhalb desinit-Blocks. Sie können das Log nach Belieben aus deminit-Block entfernen oder dort belassen.
init {
_score.value = finalScore
}- Hängen Sie in
ScoreFragmentinnerhalb vononCreateView()nach der Initialisierung vonviewModeleinen Observer für das Score-ObjektLiveDataan. Legen Sie im Lambda-Ausdruck den Punktwert auf die Textansicht für die Punktzahl fest. Entfernen Sie den Code, mit dem der Textansicht der Punktwert ausViewModeldirekt zugewiesen wird.
Code zum Hinzufügen:
// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})Zu entfernender Code:
binding.scoreText.text = viewModel.score.toString()Importieren Sie androidx.lifecycle.Observer, wenn Sie von Android Studio dazu aufgefordert werden.
- Führen Sie die App aus und spielen Sie das Spiel. Die App sollte wie zuvor funktionieren, verwendet jetzt aber
LiveDataund einen Observer, um den Score zu aktualisieren.
In dieser Aufgabe fügen Sie dem Ergebnisbildschirm die Schaltfläche Nochmal spielen hinzu und implementieren den Klick-Listener mit einem LiveData-Ereignis. Die Schaltfläche löst ein Ereignis aus, um vom Ergebnisbildschirm zum Spielbildschirm zu wechseln.
Der Startcode für die App enthält die Schaltfläche Nochmal spielen, die jedoch ausgeblendet ist.
- Ändern Sie in
res/layout/score_fragment.xmlfür die Schaltflächeplay_again_buttonden Wert des Attributsvisibilityinvisible.
<Button
android:id="@+id/play_again_button"
...
android:visibility="visible"
/>- Fügen Sie in
ScoreViewModeleinLiveData-Objekt ein, das einenBooleannamens_eventPlayAgainenthält. Mit diesem Objekt wird dasLiveData-Ereignis gespeichert, um vom Ergebnisbildschirm zum Spielbildschirm zu wechseln.
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
get() = _eventPlayAgain- Definieren Sie in
ScoreViewModelMethoden zum Festlegen und Zurücksetzen des Ereignisses,_eventPlayAgain.
fun onPlayAgain() {
_eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
_eventPlayAgain.value = false
}- Fügen Sie in
ScoreFragmenteinen Observer füreventPlayAgainhinzu. Setzen Sie den Code ans Ende vononCreateView(), vor diereturn-Anweisung. Gehen Sie im Lambda-Ausdruck zurück zum Spielbildschirm und setzen SieeventPlayAgainzurück.
// Navigates back to game when button is pressed
viewModel.eventPlayAgain.observe(this, Observer { playAgain ->
if (playAgain) {
findNavController().navigate(ScoreFragmentDirections.actionRestart())
viewModel.onPlayAgainComplete()
}
})Importieren Sie androidx.navigation.fragment.findNavController, wenn Sie von Android Studio dazu aufgefordert werden.
- Fügen Sie in
ScoreFragmentinnerhalb vononCreateView()einen Klick-Listener für die Schaltfläche PlayAgain hinzu und rufen SieviewModel.onPlayAgain()auf.
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }- Führen Sie die App aus und spielen Sie das Spiel. Wenn das Spiel beendet ist, wird auf dem Bildschirm mit dem Ergebnis die Endpunktzahl und die Schaltfläche Nochmal spielen angezeigt. Tippen Sie auf die Schaltfläche PlayAgain (Nochmal spielen). Die App leitet Sie dann zum Spielbildschirm weiter, damit Sie das Spiel noch einmal spielen können.

Gute Arbeit! Sie haben die Architektur Ihrer App so geändert, dass LiveData-Objekte im ViewModel verwendet werden, und Sie haben Beobachter an die LiveData-Objekte angehängt. LiveData benachrichtigt Beobachterobjekte, wenn sich der von LiveData gehaltene Wert ändert.
Android Studio-Projekt: GuessTheWord
LiveData
LiveDataist eine beobachtbare Datenhalterklasse, die den Lebenszyklus berücksichtigt und zu den Android-Architekturkomponenten gehört.- Mit
LiveDatakönnen Sie dafür sorgen, dass die Benutzeroberfläche automatisch aktualisiert wird, wenn sich die Daten ändern. LiveDataist beobachtbar. Das bedeutet, dass ein Beobachter wie eine Aktivität oder ein Fragment benachrichtigt werden kann, wenn sich die Daten imLiveData-Objekt ändern.LiveDataenthält Daten. Es ist ein Wrapper, der mit beliebigen Daten verwendet werden kann.LiveDataist lebenszyklusbezogen. Das bedeutet, dass nur Beobachter aktualisiert werden, die sich in einem aktiven Lebenszyklusstatus wieSTARTEDoderRESUMEDbefinden.
LiveData hinzufügen
- Ändern Sie den Typ der Datenvariablen in
ViewModelinLiveDataoderMutableLiveData.
MutableLiveData ist ein LiveData-Objekt, dessen Wert geändert werden kann. MutableLiveData ist eine generische Klasse. Sie müssen also den Datentyp angeben, den sie enthält.
- Wenn Sie den Wert der Daten ändern möchten, die von
LiveDataenthalten sind, verwenden Sie die MethodesetValue()für die VariableLiveData.
LiveData kapseln
- Die
LiveDatainViewModelsollte bearbeitbar sein. Außerhalb vonViewModelsollteLiveDatalesbar sein. Dies kann mit einem Backing Property in Kotlin implementiert werden. - Mit einer Kotlin-Backing-Property können Sie in einem Getter etwas anderes als das genaue Objekt zurückgeben.
- Um
LiveDatazu kapseln, verwenden SieprivateMutableLiveDatainnerhalb vonViewModelund geben Sie außerhalb vonViewModeleineLiveData-Backing-Property zurück.
Observable LiveData
LiveDatafolgt einem Observer-Muster. Das „beobachtbare“ Objekt ist dasLiveData-Objekt und die Beobachter sind die Methoden in den UI-Controllern, z. B. Fragmente. Immer wenn sich die inLiveDataenthaltenen Daten ändern, werden die Observer-Methoden in den UI-Controllern benachrichtigt.- Damit das
LiveDatabeobachtbar ist, hängen Sie mit der Methodeobserve()ein Beobachterobjekt an dieLiveData-Referenz in den Beobachtern (z. B. Aktivitäten und Fragmenten) an. - Dieses
LiveData-Beobachtermuster kann für die Kommunikation vomViewModelzu den UI-Controllern verwendet werden.
Udacity-Kurs:
Android-Entwicklerdokumentation:
Sonstiges:
- Backing Property in Kotlin
In diesem Abschnitt werden mögliche Hausaufgaben für Schüler und Studenten aufgeführt, die dieses Codelab im Rahmen eines von einem Kursleiter geleiteten Kurses durcharbeiten. Es liegt in der Verantwortung des Kursleiters, Folgendes zu tun:
- Weisen Sie bei Bedarf Aufgaben zu.
- Teilen Sie den Schülern/Studenten mit, wie sie Hausaufgaben abgeben können.
- Benoten Sie die Hausaufgaben.
Lehrkräfte können diese Vorschläge nach Belieben nutzen und auch andere Hausaufgaben zuweisen, die sie für angemessen halten.
Wenn Sie dieses Codelab selbst durcharbeiten, können Sie mit diesen Hausaufgaben Ihr Wissen testen.
Beantworten Sie diese Fragen
Frage 1
Wie kapseln Sie die LiveData, die in einem ViewModel gespeichert sind, sodass externe Objekte Daten lesen können, ohne sie aktualisieren zu können?
- Ändern Sie im
ViewModel-Objekt den Datentyp der Daten inprivateLiveData. Verwenden Sie eine Backing Property, um schreibgeschützte Daten vom TypMutableLiveDataverfügbar zu machen. - Ändern Sie im
ViewModel-Objekt den Datentyp der Daten inprivateMutableLiveData. Verwenden Sie eine Backing Property, um schreibgeschützte Daten vom TypLiveDataverfügbar zu machen. - Ändern Sie im UI-Controller den Datentyp der Daten in
privateMutableLiveData. Verwenden Sie eine Backing Property, um schreibgeschützte Daten vom TypLiveDataverfügbar zu machen. - Ändern Sie im
ViewModel-Objekt den Datentyp der Daten inLiveData. Verwenden Sie eine Backing Property, um schreibgeschützte Daten vom TypLiveDataverfügbar zu machen.
Frage 2
LiveData aktualisiert einen UI-Controller (z. B. ein Fragment), wenn sich der UI-Controller in einem der folgenden Status befindet:
- Fortgesetzt
- Im Hintergrund
- Pausiert
- Angehalten
Frage 3
Was ist im LiveData-Beobachtermuster das beobachtbare Element (was wird beobachtet)?
- Die Beobachtermethode
- Die Daten in einem
LiveData-Objekt - Der UI-Controller
- Das
ViewModel-Objekt
Links zu anderen Codelabs in diesem Kurs finden Sie auf der Landingpage für Android Kotlin Fundamentals-Codelabs.




