Ten moduł Codelab jest częścią kursu Android Kotlin Fundamentals. Najwięcej korzyści przyniesie Ci ukończenie wszystkich ćwiczeń w kolejności. Wszystkie ćwiczenia z tego kursu znajdziesz na stronie docelowej kursu Android Kotlin Fundamentals.
Wprowadzenie
W poprzednim laboratorium kodowania w aplikacji GuessTheWord użyto ViewModel, aby dane aplikacji przetrwały zmiany konfiguracji urządzenia. Z tego modułu dowiesz się, jak zintegrować LiveData z danymi w klasach ViewModel. LiveData, który jest jednym z komponentów architektury Androida, umożliwia tworzenie obiektów danych, które powiadamiają widoki o zmianach w bazie danych.
Aby użyć klasy LiveData, musisz skonfigurować „obserwatorów” (np. działania lub fragmenty), którzy będą śledzić zmiany w danych aplikacji. LiveData jest świadomy cyklu życia, więc aktualizuje tylko obserwatorów komponentów aplikacji, którzy są w aktywnym stanie cyklu życia.
Co warto wiedzieć
- Jak tworzyć podstawowe aplikacje na Androida w języku Kotlin.
- Jak poruszać się między miejscami docelowymi w aplikacji.
- Cykl życia działania i fragmentu.
- Jak używać obiektów
ViewModelw aplikacji. - Jak tworzyć obiekty
ViewModelza pomocą interfejsuViewModelProvider.Factory.
Czego się nauczysz
- Co sprawia, że
LiveDataobiektów jest przydatnych. - Jak dodać
LiveDatado danych przechowywanych wViewModel. - Kiedy i jak używać
MutableLiveData. - Jak dodać metody obserwatora, aby obserwować zmiany w
LiveData. - Jak enkapsulować
LiveDataza pomocą właściwości pomocniczej. - Jak komunikować się między kontrolerem interfejsu a odpowiadającym mu elementem
ViewModel.
Jakie zadania wykonasz
- Użyj
LiveDatadla słowa i wyniku w aplikacji GuessTheWord. - Dodaj obserwatorów, którzy będą reagować na zmianę słowa lub wyniku.
- Aktualizuj widoki tekstu, które wyświetlają zmienione wartości.
- Użyj wzorca
LiveDataobserwatora, aby dodać zdarzenie zakończenia gry. - Zaimplementuj przycisk Zagraj jeszcze raz.
W ćwiczeniach z programowania w lekcji 5 tworzysz aplikację GuessTheWord, zaczynając od kodu początkowego. GuessTheWord to gra w kalambury dla 2 osób, w której gracze współpracują, aby uzyskać jak najwyższy wynik.
Pierwszy gracz patrzy na słowa w aplikacji i kolejno odgrywa każde z nich, uważając, aby nie pokazać słowa drugiemu graczowi. Drugi gracz próbuje odgadnąć słowo.
Aby rozpocząć grę, pierwszy gracz otwiera aplikację na urządzeniu i widzi słowo, np. „gitara”, jak pokazano na zrzucie ekranu poniżej.
Pierwszy gracz odgrywa słowo, uważając, aby go nie wypowiedzieć.
- Gdy drugi gracz odgadnie słowo, pierwszy gracz naciśnie przycisk Got It (Mam to), co zwiększy liczbę o 1 i wyświetli kolejne słowo.
- Jeśli drugi gracz nie odgadnie słowa, pierwszy gracz naciśnie przycisk Pomiń, co zmniejszy liczbę o 1 i spowoduje przejście do następnego słowa.
- Aby zakończyć grę, naciśnij przycisk Zakończ grę. (Ta funkcja nie jest dostępna w kodzie początkowym pierwszego laboratorium w tej serii).
W tym laboratorium nauczysz się ulepszać aplikację GuessTheWord, dodając zdarzenie, które kończy grę, gdy użytkownik przejdzie przez wszystkie słowa w aplikacji. Dodasz też przycisk Zagraj ponownie w fragmencie wyniku, aby użytkownik mógł ponownie zagrać w grę.
Ekran tytułowy |
Ekran gry |
Ekran wyników |
W tym zadaniu znajdziesz i uruchomisz kod początkowy do tego ćwiczenia z programowania. Możesz użyć aplikacji GuessTheWord utworzonej w poprzednim laboratorium, lub pobrać aplikację startową.
- (Opcjonalnie) Jeśli nie używasz kodu z poprzednich ćwiczeń z programowania, pobierz kod początkowy do tych ćwiczeń. Rozpakuj kod i otwórz projekt w Android Studio.
- Uruchom aplikację i zagraj w grę.
- Zauważ, że przycisk Pomiń wyświetla następne słowo i zmniejsza wynik o 1, a przycisk Rozumiem wyświetla następne słowo i zwiększa wynik o 1. Przycisk Zakończ grę kończy grę.
LiveData to klasa przechowująca dane, które można obserwować, i która uwzględnia cykl życia. Możesz na przykład umieścić element LiveData wokół aktualnego wyniku w aplikacji GuessTheWord. W tym laboratorium dowiesz się więcej o kilku cechach elementu LiveData:
LiveDatajest obserwowalny, co oznacza, że obserwator otrzymuje powiadomienie, gdy dane przechowywane przez obiektLiveDataulegną zmianie.LiveDataprzechowuje dane;LiveDatato otoczka, której można używać z dowolnymi danymi.LiveDatauwzględnia cykl życia, co oznacza, że aktualizuje tylko obserwatorów, którzy są w aktywnym stanie cyklu życia, np.STARTEDlubRESUMED.
W tym zadaniu dowiesz się, jak opakować dowolny typ danych w obiekty LiveData, przekształcając bieżące dane o wyniku i bieżące dane o słowie w GameViewModel na LiveData. W późniejszym zadaniu dodasz do tych obiektów LiveData obserwatora i dowiesz się, jak obserwować LiveData.
Krok 1. Zmień wynik i słowo, aby używać LiveData
- W pakiecie
screens/gameotwórz plikGameViewModel. - Zmień typ zmiennych
scoreiwordnaMutableLiveData.MutableLiveDatatoLiveData, którego wartość można zmienić.MutableLiveDatato klasa ogólna, więc musisz określić typ danych, które zawiera.
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()- W pliku
GameViewModelw blokuinitzainicjuj zmiennescoreiword. Aby zmienić wartość zmiennejLiveData, użyj metodysetValue(). W języku Kotlin możesz wywołać funkcjęsetValue()za pomocą właściwościvalue.
init {
word.value = ""
score.value = 0
...
}Krok 2. Zaktualizuj odwołanie do obiektu LiveData
Zmienne score i word mają teraz typ LiveData. W tym kroku zmienisz odwołania do tych zmiennych, używając właściwości value.
- W
GameViewModelw metodzieonSkip()zmieńscorenascore.value. Zwróć uwagę na błąd dotyczący tego, żescoremoże byćnull. Ten błąd naprawisz w następnym kroku. - Aby rozwiązać ten problem, dodaj znak
nulldoscore.valuewonSkip(). Następnie wywołaj funkcjęminus()nascore, która wykonuje odejmowanie znull-bezpieczeństwem.
fun onSkip() {
if (!wordList.isEmpty()) {
score.value = (score.value)?.minus(1)
}
nextWord()
}- Zaktualizuj metodę
onCorrect()w ten sam sposób: dodaj sprawdzenienulldo zmiennejscorei użyj funkcjiplus().
fun onCorrect() {
if (!wordList.isEmpty()) {
score.value = (score.value)?.plus(1)
}
nextWord()
}- W
GameViewModelw metodzienextWord()zmień odwołaniewordnaword.value.
private fun nextWord() {
if (!wordList.isEmpty()) {
//Select and remove a word from the list
word.value = wordList.removeAt(0)
}
}- W
GameFragmentw metodzieupdateWordText()zmień odwołanie doviewModel.wordnaviewModel.word.value..
/** Methods for updating the UI **/
private fun updateWordText() {
binding.wordText.text = viewModel.word.value
}- W funkcji
GameFragmentw metodzieupdateScoreText()zmień odwołanie doviewModel.scorenaviewModel.score.value..
private fun updateScoreText() {
binding.scoreText.text = viewModel.score.value.toString()
}- W pliku
GameFragmentw metodziegameFinished()zmień odwołanie doviewModel.scorenaviewModel.score.value. Dodaj wymaganenull-safety check.
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)
}- Sprawdź, czy w kodzie nie ma błędów. Skompiluj i uruchom aplikację. Jej funkcje powinny być takie same jak wcześniej.
To zadanie jest ściśle powiązane z poprzednim, w którym przekonwertowano dane dotyczące wyników i słów na obiekty LiveData. W tym zadaniu do obiektów LiveData dołączysz obiekty Observer.
- W
GameFragment,w metodzieonCreateView()dołącz obiektObserverdo obiektuLiveDatadla bieżącego wyniku,viewModel.score. Użyj metodyobserve()i umieść kod po inicjowaniuviewModel. Użyj wyrażenia lambda, aby uprościć kod. (Wyrażenie lambda to funkcja anonimowa, która nie jest deklarowana, ale jest przekazywana natychmiast jako wyrażenie).
viewModel.score.observe(this, Observer { newScore ->
})Rozwiąż problem z odwołaniem do Observer. Aby to zrobić, kliknij Observer, naciśnij Alt+Enter (Option+Enter na komputerze Mac) i zaimportuj androidx.lifecycle.Observer.
- Obserwator, którego właśnie utworzono, otrzymuje zdarzenie, gdy zmienią się dane przechowywane przez obserwowany obiekt
LiveData. W obserwatorze zaktualizuj wynikTextView, wpisując nowy wynik.
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})- Dołącz obiekt
Observerdo obiektuLiveDatabieżącego słowa. Zrób to w taki sam sposób, w jaki dołączyłeś(-aś) obiektObserverdo bieżącego wyniku.
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
binding.wordText.text = newWord
})Gdy zmieni się wartość score lub word, wyświetlane na ekranie score lub word zostaną automatycznie zaktualizowane.
- W
GameFragmentusuń metodyupdateWordText()iupdateScoreText()oraz wszystkie odwołania do nich. Nie są już potrzebne, ponieważ widoki tekstu są aktualizowane przez metody obserwatoraLiveData. - Uruchom aplikację. Gra powinna działać tak samo jak wcześniej, ale teraz korzysta z obserwatorów
LiveDataiLiveData.
Hermetyzacja to sposób na ograniczenie bezpośredniego dostępu do niektórych pól obiektu. Gdy enkapsulujesz obiekt, udostępniasz zestaw publicznych metod, które modyfikują prywatne pola wewnętrzne. Dzięki hermetyzacji możesz kontrolować, jak inne klasy manipulują tymi polami wewnętrznymi.
W bieżącym kodzie każda klasa zewnętrzna może modyfikować zmienne score i word za pomocą właściwości value, np. używając viewModel.score.value. W aplikacji, którą tworzysz w tym laboratorium, może to nie mieć znaczenia, ale w aplikacji produkcyjnej chcesz mieć kontrolę nad danymi w obiektach ViewModel.
Tylko ViewModel powinna edytować dane w aplikacji. Kontrolery interfejsu użytkownika muszą jednak odczytywać dane, więc pola danych nie mogą być całkowicie prywatne. Do hermetyzacji danych aplikacji używasz obiektów MutableLiveData i LiveData.
MutableLiveData – LiveData:
- Dane w obiekcie
MutableLiveDatamożna zmieniać, jak sama nazwa wskazuje. WewnątrzViewModeldane powinny być edytowalne, więc używa sięMutableLiveData. - Dane w obiekcie
LiveDatamożna odczytywać, ale nie można ich zmieniać. Dane spozaViewModelpowinny być dostępne do odczytu, ale nie do edycji, dlatego powinny być udostępniane jakoLiveData.
Aby zrealizować tę strategię, użyj właściwości pomocniczej w języku Kotlin. Właściwość pomocnicza umożliwia zwrócenie z funkcji pobierającej czegoś innego niż dokładny obiekt. W tym zadaniu zaimplementujesz właściwość pomocniczą dla obiektów score i word w aplikacji GuessTheWord.
Dodawanie właściwości pomocniczej do wyniku i słowa
- W
GameViewModelustaw bieżący obiektscorejakoprivate. - Aby zachować konwencję nazewnictwa stosowaną we właściwościach pomocniczych, zmień
scorena_score. Właściwość_scorejest teraz wersją wyniku gry, którą można zmieniać i która jest używana wewnętrznie. - Utwórz publiczną wersję typu
LiveDatao nazwiescore.
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>- Wyświetla się błąd inicjowania. Ten błąd występuje, ponieważ wewnątrz
GameFragmentelementscorejest odwołaniem doLiveData, ascorenie ma już dostępu do jego funkcji ustawiającej. Więcej informacji o getterach i setterach w Kotlinie znajdziesz w artykule Getters and Setters (Gettery i settery).
Aby rozwiązać ten problem, zastąp metodęget()dla obiektuscorewGameViewModeli zwróć właściwość pomocniczą_score.
val score: LiveData<Int>
get() = _score- W
GameViewModelzmień odwołania doscorena jego wewnętrzną wersję modyfikowalną, czyli_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)
}
...
}- Zmień nazwę obiektu
wordna_wordi dodaj do niego właściwość pomocniczą, tak jak w przypadku obiektuscore.
// 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)
}
}Świetna robota! Udało Ci się zamknąć w ramce LiveData obiekty word i score.
Obecna aplikacja przechodzi do ekranu z wynikami, gdy użytkownik kliknie przycisk Zakończ grę. Chcesz też, aby po przejściu przez wszystkie słowa aplikacja przenosiła graczy na ekran z wynikami. Po tym, jak gracze skończą z ostatnim słowem, gra powinna zakończyć się automatycznie, aby użytkownik nie musiał klikać przycisku.
Aby wdrożyć tę funkcję, musisz wywołać zdarzenie i przekazać je do fragmentu z ViewModel, gdy wyświetlą się wszystkie słowa. W tym celu użyj wzorca obserwatora LiveData, aby modelować zdarzenie zakończenia gry.
Wzorzec obserwatora
Wzorzec obserwatora to wzorzec projektowy oprogramowania. Określa komunikację między obiektami: obserwowanym (czyli „obiektem” obserwacji) i obserwatorami. Obserwowany obiekt to obiekt, który powiadamia obserwatorów o zmianach w swoim stanie.

W przypadku LiveData w tej aplikacji obserwowanym obiektem (podmiotem) jest obiekt LiveData, a obserwatorami są metody w kontrolerach interfejsu, np. fragmenty. Zmiana stanu następuje za każdym razem, gdy zmieniają się dane zawarte w LiveData. Klasy LiveData są kluczowe w komunikacji z ViewModel do fragmentu.
Krok 1. Użyj LiveData do wykrywania zdarzenia zakończenia gry
W tym zadaniu użyjesz wzorca obserwatora LiveData do modelowania zdarzenia zakończenia gry.
- W
GameViewModelutwórz obiektBooleanMutableLiveDatao nazwie_eventGameFinish. Ten obiekt będzie zawierać zdarzenie zakończenia gry. - Po zainicjowaniu obiektu
_eventGameFinishutwórz i zainicjuj właściwość pomocniczą o nazwieeventGameFinish.
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
get() = _eventGameFinish- W
GameViewModeldodaj metodęonGameFinish(). W metodzie ustaw zdarzenie zakończenia gry,eventGameFinish, natrue.
/** Method for the game completed event **/
fun onGameFinish() {
_eventGameFinish.value = true
}- W
GameViewModelw metodzienextWord()zakończ grę, jeśli lista słów jest pusta.
private fun nextWord() {
if (wordList.isEmpty()) {
onGameFinish()
} else {
//Select and remove a _word from the list
_word.value = wordList.removeAt(0)
}
}- W
GameFragmentwonCreateView()po zainicjowaniuviewModeldołącz obserwatora doeventGameFinish. używaj metodyobserve(). W funkcji lambda wywołaj metodęgameFinished().
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
if (hasFinished) gameFinished()
})- Uruchom aplikację, zagraj w grę i przejdź przez wszystkie słowa. Aplikacja automatycznie przechodzi do ekranu z wynikami, zamiast pozostawać w fragmencie gry, dopóki nie klikniesz Zakończ grę.
Gdy lista słów jest pusta, ustawiana jest wartośćeventGameFinish, wywoływana jest powiązana metoda obserwatora we fragmencie gry, a aplikacja przechodzi do fragmentu ekranu. - Dodany kod spowodował problem z cyklem życia. Aby zrozumieć problem, w klasie
GameFragmentzmień w komentarz kod nawigacji w metodziegameFinished(). Pamiętaj, aby w metodzie zachować komunikatToast.
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)
}
- Uruchom aplikację, zagraj w grę i przejdź przez wszystkie słowa. U dołu ekranu gry na krótko pojawi się komunikat „Gra właśnie się skończyła”, co jest oczekiwanym zachowaniem.
Teraz obróć urządzenie lub emulator. Toast wyświetli się ponownie. Obróć urządzenie jeszcze kilka razy, a powiadomienie prawdopodobnie będzie się wyświetlać za każdym razem. To błąd, ponieważ powiadomienie powinno wyświetlać się tylko raz, po zakończeniu gry. Toast nie powinien być wyświetlany za każdym razem, gdy fragment jest ponownie tworzony. Rozwiążesz ten problem w kolejnym zadaniu.
|
|
Krok 2. Zresetuj zdarzenie zakończenia gry
Zwykle LiveData dostarcza aktualizacje do obserwatorów tylko wtedy, gdy dane się zmienią. Wyjątkiem od tego zachowania jest to, że obserwatorzy otrzymują też aktualizacje, gdy zmieniają stan z nieaktywnego na aktywny.
Dlatego w aplikacji wielokrotnie pojawia się komunikat o zakończeniu gry. Gdy po obróceniu ekranu fragment gry zostanie utworzony ponownie, przechodzi ze stanu nieaktywnego do aktywnego. Obserwator we fragmencie zostanie ponownie połączony z istniejącym ViewModel i otrzyma aktualne dane. Metoda gameFinished() zostanie ponownie wywołana i wyświetli się komunikat.
W tym zadaniu rozwiążesz ten problem i wyświetlisz komunikat tylko raz, resetując flagę eventGameFinish w GameViewModel.
- W
GameViewModeldodaj metodęonGameFinishComplete(), aby zresetować zdarzenie zakończenia gry,_eventGameFinish.
/** Method for the game completed event **/
fun onGameFinishComplete() {
_eventGameFinish.value = false
}- W pliku
GameFragmentna końcu plikugameFinished()wywołaj funkcjęonGameFinishComplete()na obiekcieviewModel. (Na razie pozostaw kod nawigacji wgameFinished()jako komentarz).
private fun gameFinished() {
...
viewModel.onGameFinishComplete()
}- Uruchom aplikację i zagraj w grę. Przejdź przez wszystkie słowa, a potem zmień orientację ekranu urządzenia. Komunikat wyświetla się tylko raz.
- W
GameFragmentw metodziegameFinished()odkomentuj kod nawigacji.
Aby odkomentować kod w Android Studio, wybierz odkomentowane wiersze i naciśnijControl+/(Command+/na komputerze 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()
}Jeśli Android Studio wyświetli odpowiedni komunikat, zaimportuj androidx.navigation.fragment.NavHostFragment.findNavController.
- Uruchom aplikację i zagraj w grę. Sprawdź, czy po przejściu przez wszystkie słowa aplikacja automatycznie przechodzi do ekranu z wynikiem końcowym.
|
|
Doskonale! Aplikacja używa LiveData, aby wywołać zdarzenie zakończenia gry i przekazać z GameViewModel do fragmentu gry informację, że lista słów jest pusta. Fragment gry przechodzi do fragmentu wyniku.
W tym zadaniu zmienisz wynik na obiekt LiveData w pliku ScoreViewModel i dołączysz do niego obserwatora. To zadanie jest podobne do tego, które wykonano podczas dodawania LiveData do GameViewModel.
Wprowadzasz te zmiany w ScoreViewModel, aby zapewnić kompletność danych i aby wszystkie dane w aplikacji korzystały z LiveData.
- W polu
ScoreViewModelzmień typ zmiennejscorenaMutableLiveData. Zmień jego nazwę zgodnie z konwencją na_scorei dodaj właściwość pomocniczą.
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
get() = _score- W
ScoreViewModel, w blokuinit, zainicjuj_score. Możesz usunąć lub pozostawić log w blokuinit.
init {
_score.value = finalScore
}- W
ScoreFragmentwonCreateView()po zainicjowaniuviewModeldołącz obserwatora obiektu wynikuLiveData. W wyrażeniu lambda ustaw wartość wyniku w widoku tekstu wyniku. Usuń zViewModelkod, który bezpośrednio przypisuje widokowi tekstu wartość wyniku.
Kod do dodania:
// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})Kod do usunięcia:
binding.scoreText.text = viewModel.score.toString()Gdy Android Studio wyświetli odpowiedni komunikat, zaimportuj plik androidx.lifecycle.Observer.
- Uruchom aplikację i zagraj w grę. Aplikacja powinna działać jak wcześniej, ale teraz do aktualizowania wyniku używa
LiveDatai obserwatora.
W tym zadaniu dodasz do ekranu z wynikami przycisk Zagraj jeszcze raz i zastosujesz detektor kliknięć za pomocą zdarzenia LiveData. Przycisk wywołuje zdarzenie, które powoduje przejście z ekranu wyniku do ekranu gry.
Kod początkowy aplikacji zawiera przycisk Zagraj ponownie, ale jest on ukryty.
- W
res/layout/score_fragment.xmlw przypadku przyciskuplay_again_buttonzmień wartość atrybutuvisibilitynavisible.
<Button
android:id="@+id/play_again_button"
...
android:visibility="visible"
/>- W sekcji
ScoreViewModeldodaj obiektLiveData, który będzie zawierać elementBooleano nazwie_eventPlayAgain. Ten obiekt służy do zapisywania zdarzeniaLiveData, aby przejść z ekranu z wynikami do ekranu gry.
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
get() = _eventPlayAgain- W
ScoreViewModelzdefiniuj metody ustawiania i resetowania zdarzenia_eventPlayAgain.
fun onPlayAgain() {
_eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
_eventPlayAgain.value = false
}- W
ScoreFragmentdodaj obserwatora doeventPlayAgain. Umieść kod na końcuonCreateView(), przed instrukcjąreturn. W wyrażeniu lambda wróć do ekranu gry i zresetuj wartośćeventPlayAgain.
// Navigates back to game when button is pressed
viewModel.eventPlayAgain.observe(this, Observer { playAgain ->
if (playAgain) {
findNavController().navigate(ScoreFragmentDirections.actionRestart())
viewModel.onPlayAgainComplete()
}
})Po wyświetleniu prośby w Android Studio zaimportuj androidx.navigation.fragment.findNavController.
- W
ScoreFragmentwonCreateView()dodaj odbiornik kliknięć do przycisku PlayAgain i wywołaj funkcjęviewModel.onPlayAgain().
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }- Uruchom aplikację i zagraj w grę. Po zakończeniu gry na ekranie wyników pojawi się ostateczny wynik i przycisk Zagraj ponownie. Kliknij przycisk PlayAgain, a aplikacja przeniesie Cię na ekran gry, aby umożliwić Ci ponowne rozpoczęcie rozgrywki.

Dobra robota! Zmieniasz architekturę aplikacji, aby używać LiveDataobiektów w ViewModel, i dołączasz obserwatorów do obiektów LiveData. LiveData powiadamia obiekty obserwujące, gdy wartość przechowywana przez LiveData ulegnie zmianie.
Projekt Android Studio: GuessTheWord
LiveData
LiveDatato klasa przechowująca dane, które można obserwować, i która jest powiązana z cyklem życia. Jest to jeden z komponentów architektury Androida.- Możesz użyć
LiveData, aby włączyć automatyczne aktualizowanie interfejsu użytkownika po zmianie danych. LiveDatajest obserwowalny, co oznacza, że obserwator, np. aktywność lub fragment, może otrzymywać powiadomienia o zmianach danych przechowywanych przez obiektLiveData.LiveDataprzechowuje dane; jest to kontener, którego można używać z dowolnymi danymi.LiveDatauwzględnia cykl życia, co oznacza, że aktualizuje tylko obserwatorów, którzy są w aktywnym stanie cyklu życia, np.STARTEDlubRESUMED.
Aby dodać LiveData
- Zmień typ zmiennych danych w
ViewModelnaLiveDatalubMutableLiveData.
MutableLiveData to obiekt LiveData, którego wartość można zmienić. MutableLiveData to klasa ogólna, więc musisz określić typ danych, które zawiera.
- Aby zmienić wartość danych przechowywanych przez zmienną
LiveData, użyj metodysetValue()w zmiennejLiveData.
Enkapsulacja LiveData
- Wartość
LiveDataw obrębie elementuViewModelpowinna być edytowalna. PozaViewModelelementLiveDatapowinien być czytelny. Można to zaimplementować za pomocą właściwości pomocniczej w języku Kotlin. - Właściwość pomocnicza w Kotlinie umożliwia zwracanie z metody pobierającej czegoś innego niż dokładny obiekt.
- Aby zamknąć element
LiveData, użyjprivateMutableLiveDatawewnątrz elementuViewModeli zwróć właściwośćLiveDatabacking poza elementemViewModel.
Obserwowalne obiekty LiveData
LiveDatajest zgodny ze wzorcem obserwatora. „Obserwowany” to obiektLiveData, a obserwatorami są metody w kontrolerach interfejsu, np. fragmenty. Gdy dane zawarte wLiveDataulegną zmianie, metody obserwatora w kontrolerach interfejsu użytkownika otrzymają powiadomienie.- Aby obiekt
LiveDatabył obserwowalny, dołącz do niego obiekt obserwatora w obserwatorach (np. w aktywnościach i fragmentach) za pomocą metodyobserve().LiveData - Ten wzorzec
LiveDataobserwatora może być używany do komunikacji z kontrolerami interfejsu.ViewModel
Kurs Udacity:
Dokumentacja dla deweloperów aplikacji na Androida:
Inne:
- Właściwość pomocnicza w języku Kotlin
W tej sekcji znajdziesz listę możliwych zadań domowych dla uczniów, którzy wykonują ten moduł w ramach kursu prowadzonego przez instruktora. Nauczyciel musi:
- W razie potrzeby przypisz pracę domową.
- Poinformuj uczniów, jak przesyłać projekty.
- Oceń zadania domowe.
Instruktorzy mogą korzystać z tych sugestii w dowolnym zakresie i mogą zadawać inne zadania domowe, które uznają za odpowiednie.
Jeśli wykonujesz ten kurs samodzielnie, możesz użyć tych zadań domowych, aby sprawdzić swoją wiedzę.
Odpowiedz na te pytania
Pytanie 1
Jak zamknąć LiveData w ViewModel, aby obiekty zewnętrzne mogły odczytywać dane bez możliwości ich aktualizacji?
- W obiekcie
ViewModelzmień typ danych naprivateLiveData. Użyj właściwości pomocniczej, aby udostępnić dane tylko do odczytu typuMutableLiveData. - W obiekcie
ViewModelzmień typ danych naprivateMutableLiveData. Użyj właściwości pomocniczej, aby udostępnić dane tylko do odczytu typuLiveData. - W kontrolerze interfejsu zmień typ danych na
privateMutableLiveData. Użyj właściwości pomocniczej, aby udostępnić dane tylko do odczytu typuLiveData. - W obiekcie
ViewModelzmień typ danych naLiveData. Użyj właściwości pomocniczej, aby udostępnić dane tylko do odczytu typuLiveData.
Pytanie 2
LiveData aktualizuje kontroler interfejsu (np. fragment), jeśli jest on w jednym z tych stanów:
- Wznowiono
- W tle
- Wstrzymano
- Zatrzymano
Pytanie 3
W LiveData wzorcu obserwatora co jest obserwowanym elementem (co jest obserwowane)?
- Metoda obserwacyjna
- Dane w obiekcie
LiveData - Kontroler interfejsu
- Obiekt
ViewModel
Rozpocznij kolejną lekcję:
Linki do innych ćwiczeń z tego kursu znajdziesz na stronie docelowej ćwiczeń z podstaw języka Kotlin na Androidzie.




