Android Kotlin Fundamentals 05.2: LiveData e osservatori LiveData

Questo codelab fa parte del corso Android Kotlin Fundamentals. Per ottenere il massimo valore da questo corso, ti consigliamo di seguire le codelab in sequenza. Tutti i codelab del corso sono elencati nella pagina di destinazione dei codelab Android Kotlin Fundamentals.

Introduzione

Nel codelab precedente, hai utilizzato un ViewModel nell'app GuessTheWord per consentire ai dati dell'app di sopravvivere alle modifiche alla configurazione del dispositivo. In questo codelab, imparerai a integrare LiveData con i dati nelle classi ViewModel. LiveData, uno dei componenti dell'architettura Android, ti consente di creare oggetti di dati che notificano alle visualizzazioni le modifiche al database sottostante.

Per utilizzare la classe LiveData, devi configurare "osservatori" (ad esempio attività o frammenti) che osservano le modifiche ai dati dell'app. LiveData è consapevole del ciclo di vita, quindi aggiorna solo gli osservatori dei componenti dell'app che si trovano in uno stato del ciclo di vita attivo.

Cosa devi già sapere

  • Come creare app per Android di base in Kotlin.
  • Come spostarsi tra le destinazioni dell'app.
  • Ciclo di vita di attività e frammenti.
  • Come utilizzare gli oggetti ViewModel nella tua app.
  • Come creare oggetti ViewModel utilizzando l'interfaccia ViewModelProvider.Factory.

Obiettivi didattici

  • Che cosa rende utili gli oggetti LiveData.
  • Come aggiungere LiveData ai dati archiviati in un ViewModel.
  • Quando e come utilizzare MutableLiveData.
  • Come aggiungere metodi di osservazione per osservare le modifiche in LiveData.
  • Come incapsulare LiveData utilizzando una proprietà di supporto.
  • Come comunicare tra un controller UI e il relativo ViewModel.

In questo lab proverai a:

  • Utilizza LiveData per la parola e il punteggio nell'app IndovinaParola.
  • Aggiungi osservatori che notano quando la parola o il punteggio cambia.
  • Aggiorna le visualizzazioni di testo che mostrano i valori modificati.
  • Utilizza il pattern observer LiveData per aggiungere un evento di fine partita.
  • Implementa il pulsante Gioca di nuovo.

Nei codelab della lezione 5, sviluppi l'app IndovinaParola, partendo dal codice iniziale. IndovinaParola è un gioco in stile Sarabanda per due giocatori, in cui i giocatori collaborano per ottenere il punteggio più alto possibile.

Il primo giocatore guarda le parole nell'app e le mima a turno, assicurandosi di non mostrarle al secondo giocatore. Il secondo giocatore cerca di indovinare la parola.

Per giocare, il primo giocatore apre l'app sul dispositivo e vede una parola, ad esempio "chitarra", come mostrato nello screenshot di seguito.

Il primo giocatore recita la parola, facendo attenzione a non dirla.

  • Quando il secondo giocatore indovina la parola correttamente, il primo giocatore preme il pulsante Indovinato, che aumenta il conteggio di uno e mostra la parola successiva.
  • Se il secondo giocatore non riesce a indovinare la parola, il primo giocatore preme il pulsante Salta, che diminuisce il conteggio di uno e passa alla parola successiva.
  • Per terminare la partita, premi il pulsante Termina partita. Questa funzionalità non è presente nel codice iniziale del primo codelab della serie.

In questo codelab, migliorerai l'app GuessTheWord aggiungendo un evento per terminare la partita quando l'utente ha esaurito tutte le parole dell'app. Aggiungerai anche un pulsante Gioca di nuovo nel fragment del punteggio, in modo che l'utente possa giocare di nuovo.

Schermata del titolo

Schermata di gioco

Schermata del punteggio

In questa attività, individua ed esegui il codice iniziale per questo codelab. Puoi utilizzare l'app IndovinaParola che hai creato nel codelab precedente come codice iniziale oppure scaricare un'app iniziale.

  1. (Facoltativo) Se non utilizzi il codice del codelab precedente, scarica il codice iniziale per questo codelab. Decomprimi il codice e apri il progetto in Android Studio.
  2. Esegui l'app e gioca.
  3. Tieni presente che il pulsante Salta mostra la parola successiva e diminuisce il punteggio di uno, mentre il pulsante Capito mostra la parola successiva e aumenta il punteggio di uno. Il pulsante Termina partita termina la partita.

LiveData è una classe di contenitore di dati osservabile che riconosce il ciclo di vita. Ad esempio, puoi racchiudere un LiveData intorno al punteggio attuale nell'app IndovinaParola. In questo codelab, scoprirai diverse caratteristiche di LiveData:

  • LiveData è osservabile, il che significa che un osservatore riceve una notifica quando i dati contenuti nell'oggetto LiveData cambiano.
  • LiveData contiene i dati; LiveData è un wrapper che può essere utilizzato con qualsiasi dato
  • LiveData è consapevole del ciclo di vita, il che significa che aggiorna solo gli osservatori che si trovano in uno stato del ciclo di vita attivo, ad esempio STARTED o RESUMED.

In questa attività, imparerai a racchiudere qualsiasi tipo di dati in oggetti LiveData convertendo i dati relativi al punteggio attuale e alla parola attuale in GameViewModel in LiveData. In un'attività successiva, aggiungi un osservatore a questi oggetti LiveData e scopri come osservare LiveData.

Passaggio 1: modifica il punteggio e la parola per utilizzare LiveData

  1. Nel pacchetto screens/game, apri il file GameViewModel.
  2. Modifica il tipo delle variabili score e word in MutableLiveData.

    MutableLiveData è un LiveData il cui valore può essere modificato. MutableLiveData è una classe generica, quindi devi specificare il tipo di dati che contiene.
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()
  1. In GameViewModel, all'interno del blocco init, inizializza score e word. Per modificare il valore di una variabile LiveData, utilizza il metodo setValue() sulla variabile. In Kotlin, puoi chiamare setValue() utilizzando la proprietà value.
init {

   word.value = ""
   score.value = 0
  ...
}

Passaggio 2: aggiorna il riferimento all'oggetto LiveData

Le variabili score e word ora sono di tipo LiveData. In questo passaggio, modifichi i riferimenti a queste variabili utilizzando la proprietà value.

  1. In GameViewModel, nel metodo onSkip(), modifica score in score.value. Nota l'errore relativo a score che potrebbe essere null. Correggi questo errore nel passaggio successivo.
  2. Per risolvere l'errore, aggiungi un controllo null a score.value in onSkip(). Poi chiama la funzione minus() su score, che esegue la sottrazione con null-safety.
fun onSkip() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.minus(1)
   }
   nextWord()
}
  1. Aggiorna il metodo onCorrect() nello stesso modo: aggiungi un controllo null alla variabile score e utilizza la funzione plus().
fun onCorrect() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.plus(1)
   }
   nextWord()
}
  1. In GameViewModel, all'interno del metodo nextWord(), modifica il riferimento word in word.value.
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       word.value = wordList.removeAt(0)
   }
}
  1. In GameFragment, all'interno del metodo updateWordText(), modifica il riferimento a viewModel.word in viewModel.word.value.
/** Methods for updating the UI **/
private fun updateWordText() {
   binding.wordText.text = viewModel.word.value
}
  1. In GameFragment, all'interno del metodo updateScoreText(), modifica il riferimento a viewModel.score in viewModel.score.value.
private fun updateScoreText() {
   binding.scoreText.text = viewModel.score.value.toString()
}
  1. In GameFragment, all'interno del metodo gameFinished(), modifica il riferimento da viewModel.score a viewModel.score.value. Aggiungi il controllo di sicurezza null richiesto.
private fun gameFinished() {
   Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
   val action = GameFragmentDirections.actionGameToScore()
   action.score = viewModel.score.value?:0
   NavHostFragment.findNavController(this).navigate(action)
}
  1. Assicurati che non ci siano errori nel codice. Compila ed esegui l'app. La funzionalità dell'app dovrebbe essere la stessa di prima.

Questa attività è strettamente correlata a quella precedente, in cui hai convertito i dati di punteggio e parole in oggetti LiveData. In questa attività, collegherai gli oggetti Observer agli oggetti LiveData.

  1. In GameFragment, all'interno del metodo onCreateView(), collega un oggetto Observer all'oggetto LiveData per il punteggio corrente, viewModel.score. Utilizza il metodo observe() e inserisci il codice dopo l'inizializzazione di viewModel. Utilizza un'espressione lambda per semplificare il codice. Un'espressione lambda è una funzione anonima che non viene dichiarata, ma viene passata immediatamente come espressione.
viewModel.score.observe(this, Observer { newScore ->
})

Risolvi il riferimento a Observer. Per farlo, fai clic su Observer, premi Alt+Enter (Option+Enter su Mac) e importa androidx.lifecycle.Observer.

  1. L'osservatore che hai appena creato riceve un evento quando cambiano i dati contenuti nell'oggetto LiveData osservato. All'interno dell'osservatore, aggiorna il punteggio TextView con il nuovo punteggio.
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})
  1. Allega un oggetto Observer all'oggetto parola corrente LiveData. Fallo nello stesso modo in cui hai allegato un oggetto Observer alla partitura corrente.
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
   binding.wordText.text = newWord
})

Quando il valore di score o di word cambia, il valore di score o word visualizzato sullo schermo ora si aggiorna automaticamente.

  1. In GameFragment, elimina i metodi updateWordText() e updateScoreText() e tutti i relativi riferimenti. Non ne hai più bisogno, perché le visualizzazioni di testo vengono aggiornate dai metodi di osservazione LiveData.
  2. Esegui l'app. L'app di gioco dovrebbe funzionare esattamente come prima, ma ora utilizza gli osservatori LiveData e LiveData.

L'incapsulamento è un modo per limitare l'accesso diretto ad alcuni campi di un oggetto. Quando incapsuli un oggetto, esponi un insieme di metodi pubblici che modificano i campi interni privati. Utilizzando l'incapsulamento, controlli il modo in cui le altre classi manipolano questi campi interni.

Nel codice attuale, qualsiasi classe esterna può modificare le variabili score e word utilizzando la proprietà value, ad esempio utilizzando viewModel.score.value. Potrebbe non essere importante nell'app che stai sviluppando in questo codelab, ma in un'app di produzione vuoi controllare i dati negli oggetti ViewModel.

Solo ViewModel deve modificare i dati nella tua app. Tuttavia, i controller UI devono leggere i dati, quindi i campi di dati non possono essere completamente privati. Per incapsulare i dati della tua app, utilizzi gli oggetti MutableLiveData e LiveData.

MutableLiveData contro LiveData:

  • I dati in un oggetto MutableLiveData possono essere modificati, come suggerisce il nome. All'interno di ViewModel, i dati devono essere modificabili, quindi utilizza MutableLiveData.
  • I dati in un oggetto LiveData possono essere letti, ma non modificati. Al di fuori di ViewModel, i dati devono essere leggibili, ma non modificabili, quindi devono essere esposti come LiveData.

Per implementare questa strategia, utilizzi una proprietà di backing Kotlin. Una proprietà di supporto consente di restituire qualcosa da un getter diverso dall'oggetto esatto. In questa attività, implementerai una proprietà di supporto per gli oggetti score e word nell'app IndovinaParola.

Aggiungere una proprietà di supporto a punteggio e parola

  1. In GameViewModel, rendi l'oggetto score corrente private.
  2. Per seguire la convenzione di denominazione utilizzata nelle proprietà di backup, modifica score in _score. La proprietà _score è ora la versione modificabile del punteggio di gioco, da utilizzare internamente.
  3. Crea una versione pubblica del tipo LiveData, denominata score.
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
  1. Viene visualizzato un errore di inizializzazione. Questo errore si verifica perché all'interno di GameFragment, score è un riferimento LiveData e score non può più accedere al relativo setter. Per scoprire di più su getter e setter in Kotlin, consulta Getter e setter.

    Per risolvere l'errore, esegui l'override del metodo get() per l'oggetto score in GameViewModel e restituisci la proprietà di supporto, _score.
val score: LiveData<Int>
   get() = _score
  1. In GameViewModel, modifica i riferimenti di score alla relativa versione interna modificabile, _score.
init {
   ...
   _score.value = 0
   ...
}

...
fun onSkip() {
   if (!wordList.isEmpty()) {
       _score.value = (score.value)?.minus(1)
   }
  ...
}

fun onCorrect() {
   if (!wordList.isEmpty()) {
       _score.value = (score.value)?.plus(1)
   }
   ...
}
  1. Rinomina l'oggetto word in _word e aggiungi una proprietà di supporto, come hai fatto per l'oggetto 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)
   }
}

Ottimo lavoro, hai incapsulato gli oggetti LiveDataword e score.

L'app attuale passa alla schermata del punteggio quando l'utente tocca il pulsante Fine partita. Inoltre, vuoi che l'app passi alla schermata del punteggio quando i giocatori hanno completato tutti i cicli delle parole. Dopo che i giocatori hanno finito con l'ultima parola, vuoi che la partita termini automaticamente in modo che l'utente non debba toccare il pulsante.

Per implementare questa funzionalità, è necessario che venga attivato un evento e comunicato al fragment da ViewModel quando sono state mostrate tutte le parole. Per farlo, utilizza il LiveData pattern observer per modellare un evento di fine partita.

Il pattern Observer

Il pattern Observer è un pattern di progettazione del software. Specifica la comunicazione tra gli oggetti: un osservabile (il "soggetto" dell'osservazione) e gli osservatori. Un osservabile è un oggetto che notifica agli osservatori le modifiche al suo stato.

Nel caso di LiveData in questa app, l'osservabile (soggetto) è l'oggetto LiveData e gli osservatori sono i metodi nei controller UI, come i fragment. Una modifica dello stato si verifica ogni volta che cambiano i dati inclusi in LiveData. Le classi LiveData sono fondamentali per la comunicazione da ViewModel al frammento.

Passaggio 1: utilizza LiveData per rilevare un evento di fine partita

In questa attività, utilizzi il pattern observer LiveData per modellare un evento di fine partita.

  1. In GameViewModel, crea un oggetto Boolean MutableLiveData chiamato _eventGameFinish. Questo oggetto conterrà l'evento di fine partita.
  2. Dopo aver inizializzato l'oggetto _eventGameFinish, crea e inizializza una proprietà di supporto chiamata eventGameFinish.
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
   get() = _eventGameFinish
  1. In GameViewModel, aggiungi un metodo onGameFinish(). Nel metodo, imposta l'evento di fine partita, eventGameFinish, su true.
/** Method for the game completed event **/
fun onGameFinish() {
   _eventGameFinish.value = true
}
  1. In GameViewModel, all'interno del metodo nextWord(), termina la partita se l'elenco di parole è vuoto.
private fun nextWord() {
   if (wordList.isEmpty()) {
       onGameFinish()
   } else {
       //Select and remove a _word from the list
       _word.value = wordList.removeAt(0)
   }
}
  1. In GameFragment, all'interno di onCreateView(), dopo aver inizializzato viewModel, collega un osservatore a eventGameFinish. Utilizza il metodo observe(). All'interno della funzione lambda, chiama il metodo gameFinished().
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
   if (hasFinished) gameFinished()
})
  1. Esegui l'app, gioca e ripassa tutte le parole. L'app passa automaticamente alla schermata del punteggio, anziché rimanere nel frammento di gioco finché non tocchi Termina partita.

    Una volta svuotato l'elenco di parole, viene impostato eventGameFinish, viene chiamato il metodo observer associato nel frammento di gioco e l'app passa al frammento di schermata.
  2. Il codice che hai aggiunto ha introdotto un problema del ciclo di vita. Per comprendere il problema, nella classe GameFragment, commenta il codice di navigazione nel metodo gameFinished(). Assicurati di mantenere il messaggio Toast nel metodo.
private fun gameFinished() {
       Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
//        val action = GameFragmentDirections.actionGameToScore()
//        action.score = viewModel.score.value?:0
//        NavHostFragment.findNavController(this).navigate(action)
   }
  1. Esegui l'app, gioca e ripassa tutte le parole. Nella parte inferiore della schermata di gioco viene visualizzato brevemente un messaggio di notifica che indica "La partita è appena terminata", come previsto.

Ora ruota il dispositivo o l'emulatore. Il messaggio toast viene visualizzato di nuovo. Ruota il dispositivo altre volte e probabilmente vedrai il messaggio ogni volta. Si tratta di un bug, perché il messaggio di notifica dovrebbe essere visualizzato una sola volta, al termine della partita. Il toast non deve essere visualizzato ogni volta che il frammento viene ricreato. Risolvi questo problema nella prossima attività.

Passaggio 2: reimposta l'evento di fine partita

In genere, LiveData invia aggiornamenti agli osservatori solo quando i dati cambiano. Un'eccezione a questo comportamento è che gli osservatori ricevono aggiornamenti anche quando passano da uno stato inattivo a uno attivo.

Per questo motivo, il messaggio di notifica di fine partita viene attivato ripetutamente nell'app. Quando il frammento di gioco viene ricreato dopo una rotazione dello schermo, passa da uno stato inattivo a uno stato attivo. L'observer nel fragment viene riconnesso all'ViewModel esistente e riceve i dati correnti. Il metodo gameFinished() viene riattivato e viene visualizzato il messaggio di notifica.

In questa attività, risolverai il problema e visualizzerai il messaggio di notifica solo una volta reimpostando il flag eventGameFinish in GameViewModel.

  1. In GameViewModel, aggiungi un metodo onGameFinishComplete() per reimpostare l'evento di completamento della partita, _eventGameFinish.
/** Method for the game completed event **/

fun onGameFinishComplete() {
   _eventGameFinish.value = false
}
  1. In GameFragment, alla fine di gameFinished(), chiama onGameFinishComplete() sull'oggetto viewModel. Per ora lascia il codice di navigazione commentato in gameFinished().
private fun gameFinished() {
   ...
   viewModel.onGameFinishComplete()
}
  1. Esegui l'app e gioca. Leggi tutte le parole, quindi cambia l'orientamento dello schermo del dispositivo. Il messaggio popup viene visualizzato una sola volta.
  2. In GameFragment, all'interno del metodo gameFinished(), rimuovi il commento dal codice di navigazione.

    Per rimuovere il commento in Android Studio, seleziona le righe commentate e premi Control+/ (Command+/ su 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()
}

Se richiesto da Android Studio, importa androidx.navigation.fragment.NavHostFragment.findNavController.

  1. Esegui l'app e gioca. Assicurati che l'app passi automaticamente alla schermata del punteggio finale dopo che hai completato tutte le parole.

Ottimo lavoro! La tua app utilizza LiveData per attivare un evento di fine partita per comunicare da GameViewModel al frammento di gioco che l'elenco di parole è vuoto. Il frammento di gioco passa quindi al frammento del punteggio.

In questa attività, modifichi il punteggio in un oggetto LiveData in ScoreViewModel e gli colleghi un osservatore. Questa attività è simile a quella che hai svolto quando hai aggiunto LiveData a GameViewModel.

Apporti queste modifiche a ScoreViewModel per completezza, in modo che tutti i dati della tua app utilizzino LiveData.

  1. In ScoreViewModel, modifica il tipo di variabile score in MutableLiveData. Rinominalo per convenzione in _score e aggiungi una proprietà di supporto.
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
   get() = _score
  1. In ScoreViewModel, all'interno del blocco init, inizializza _score. Puoi rimuovere o lasciare il log nel blocco init come preferisci.
init {
   _score.value = finalScore
}
  1. In ScoreFragment, all'interno di onCreateView(), dopo aver inizializzato viewModel, collega un osservatore per l'oggetto LiveData del punteggio. All'interno dell'espressione lambda, imposta il valore del punteggio sulla visualizzazione del testo del punteggio. Rimuovi il codice che assegna direttamente la visualizzazione del testo con il valore del punteggio da ViewModel.

Codice da aggiungere:

// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})

Codice da rimuovere:

binding.scoreText.text = viewModel.score.toString()

Quando richiesto da Android Studio, importa androidx.lifecycle.Observer.

  1. Esegui l'app e gioca. L'app dovrebbe funzionare come prima, ma ora utilizza LiveData e un osservatore per aggiornare il punteggio.

In questa attività, aggiungi un pulsante Gioca di nuovo alla schermata del punteggio e implementa il relativo listener di clic utilizzando un evento LiveData. Il pulsante attiva un evento per passare dalla schermata del punteggio alla schermata di gioco.

Il codice iniziale dell'app include il pulsante Gioca di nuovo, ma è nascosto.

  1. In res/layout/score_fragment.xml, per il pulsante play_again_button, modifica il valore dell'attributo visibility in visible.
<Button
   android:id="@+id/play_again_button"
...
   android:visibility="visible"
 />
  1. In ScoreViewModel, aggiungi un oggetto LiveData per contenere un Boolean chiamato _eventPlayAgain. Questo oggetto viene utilizzato per salvare l'evento LiveData per passare dalla schermata del punteggio a quella di gioco.
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
   get() = _eventPlayAgain
  1. In ScoreViewModel, definisci i metodi per impostare e reimpostare l'evento, _eventPlayAgain.
fun onPlayAgain() {
   _eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
   _eventPlayAgain.value = false
}
  1. In ScoreFragment, aggiungi un osservatore per eventPlayAgain. Inserisci il codice alla fine di onCreateView(), prima dell'estratto conto return. All'interno dell'espressione lambda, torna alla schermata di gioco e reimposta eventPlayAgain.
// Navigates back to game when button is pressed
viewModel.eventPlayAgain.observe(this, Observer { playAgain ->
   if (playAgain) {
      findNavController().navigate(ScoreFragmentDirections.actionRestart())
       viewModel.onPlayAgainComplete()
   }
})

Importa androidx.navigation.fragment.findNavController quando richiesto da Android Studio.

  1. In ScoreFragment, all'interno di onCreateView(), aggiungi un listener di clic al pulsante PlayAgain e chiama viewModel.onPlayAgain().
binding.playAgainButton.setOnClickListener {  viewModel.onPlayAgain()  }
  1. Esegui l'app e gioca. Al termine della partita, la schermata del punteggio mostra il punteggio finale e il pulsante Gioca di nuovo. Tocca il pulsante PlayAgain e l'app ti reindirizza alla schermata di gioco per poter giocare di nuovo.

Ben fatto! Hai modificato l'architettura della tua app per utilizzare gli oggetti LiveData in ViewModel e hai collegato gli osservatori agli oggetti LiveData. LiveData notifica gli oggetti osservatori quando cambia il valore contenuto in LiveData.

Progetto Android Studio: GuessTheWord

LiveData

  • LiveData è una classe di contenitore di dati osservabile che riconosce il ciclo di vita, uno dei componenti dell'architettura Android.
  • Puoi utilizzare LiveData per consentire all'interfaccia utente di aggiornarsi automaticamente quando i dati vengono aggiornati.
  • LiveData è osservabile, il che significa che un osservatore come un'attività o un frammento può ricevere una notifica quando i dati contenuti nell'oggetto LiveData cambiano.
  • LiveData contiene dati; è un wrapper che può essere utilizzato con qualsiasi dato.
  • LiveData è consapevole del ciclo di vita, il che significa che aggiorna solo gli osservatori che si trovano in uno stato del ciclo di vita attivo, ad esempio STARTED o RESUMED.

Per aggiungere LiveData

  • Modifica il tipo delle variabili di dati in ViewModel in LiveData o MutableLiveData.

MutableLiveData è un oggetto LiveData il cui valore può essere modificato. MutableLiveData è una classe generica, quindi devi specificare il tipo di dati che contiene.

  • Per modificare il valore dei dati contenuti in LiveData, utilizza il metodo setValue() sulla variabile LiveData.

Per incapsulare LiveData

  • LiveData all'interno di ViewModel deve essere modificabile. Al di fuori di ViewModel, LiveData deve essere leggibile. Questa operazione può essere implementata utilizzando una proprietà di supporto Kotlin.
  • Una proprietà di supporto Kotlin ti consente di restituire qualcosa da un getter diverso dall'oggetto esatto.
  • Per incapsulare LiveData, utilizza private MutableLiveData all'interno di ViewModel e restituisci una proprietà di supporto LiveData all'esterno di ViewModel.

Observable LiveData

  • LiveData segue un pattern di osservazione. L'"osservabile" è l'oggetto LiveData e gli osservatori sono i metodi nei controller UI, come i fragment. Ogni volta che i dati racchiusi in LiveData cambiano, i metodi di osservazione nei controller UI vengono notificati.
  • Per rendere osservabile LiveData, collega un oggetto osservatore al riferimento LiveData negli osservatori (come attività e frammenti) utilizzando il metodo observe().
  • Questo pattern dell'observer LiveData può essere utilizzato per comunicare da ViewModel ai controller UI.

Corso Udacity:

Documentazione per sviluppatori Android:

Altro:

Questa sezione elenca i possibili compiti a casa per gli studenti che seguono questo codelab nell'ambito di un corso guidato da un insegnante. Spetta all'insegnante:

  • Assegna i compiti, se richiesto.
  • Comunica agli studenti come inviare i compiti.
  • Valuta i compiti a casa.

Gli insegnanti possono utilizzare questi suggerimenti nella misura che ritengono opportuna e sono liberi di assegnare qualsiasi altro compito a casa che ritengono appropriato.

Se stai seguendo questo codelab in autonomia, sentiti libero di utilizzare questi compiti per casa per mettere alla prova le tue conoscenze.

Rispondi a queste domande

Domanda 1

Come si incapsula LiveData memorizzato in un ViewModel in modo che gli oggetti esterni possano leggere i dati senza poterli aggiornare?

  • All'interno dell'oggetto ViewModel, modifica il tipo di dati in private LiveData. Utilizza una proprietà di supporto per esporre i dati di sola lettura di tipo MutableLiveData.
  • All'interno dell'oggetto ViewModel, modifica il tipo di dati in private MutableLiveData. Utilizza una proprietà di supporto per esporre i dati di sola lettura di tipo LiveData.
  • All'interno del controller dell'interfaccia utente, modifica il tipo di dati in private MutableLiveData. Utilizza una proprietà di supporto per esporre i dati di sola lettura di tipo LiveData.
  • All'interno dell'oggetto ViewModel, modifica il tipo di dati in LiveData. Utilizza una proprietà di supporto per esporre i dati di sola lettura di tipo LiveData.

Domanda 2

LiveData aggiorna un controller UI (ad esempio un fragment) se il controller UI si trova in uno dei seguenti stati?

  • Ripristinata
  • In background
  • In pausa
  • Arrestata

Domanda 3

Nel pattern observer LiveData, qual è l'elemento osservabile (cosa viene osservato)?

  • Metodo dell'osservatore
  • I dati in un oggetto LiveData
  • Il controller UI
  • L'oggetto ViewModel

Inizia la lezione successiva: 5.3: Data binding con ViewModel e LiveData

Per i link ad altri codelab di questo corso, consulta la pagina di destinazione dei codelab di Android Kotlin Fundamentals.