Principes de base d'Android en Kotlin 05.2 : LiveData et observateurs LiveData

Cet atelier de programmation fait partie du cours Principes de base d'Android en Kotlin. Vous tirerez pleinement parti de ce cours en suivant les ateliers de programmation dans l'ordre. Tous les ateliers de programmation du cours sont listés sur la page de destination des ateliers de programmation Principes de base d'Android en Kotlin.

Introduction

Dans l'atelier de programmation précédent, vous avez utilisé un ViewModel dans l'application GuessTheWord pour permettre aux données de l'application de survivre aux changements de configuration de l'appareil. Dans cet atelier de programmation, vous allez apprendre à intégrer LiveData aux données des classes ViewModel. LiveData, qui fait partie des composants d'architecture Android, vous permet de créer des objets de données qui avertissent les vues lorsque la base de données sous-jacente change.

Pour utiliser la classe LiveData, vous configurez des "observateurs" (par exemple, des activités ou des fragments) qui observent les modifications apportées aux données de l'application. LiveData tient compte du cycle de vie, ce qui signifie qu'il ne met à jour que les observateurs de composants d'application dont l'état du cycle de vie est actif.

Ce que vous devez déjà savoir

  • Vous savez comment créer des applications Android de base en langage Kotlin.
  • Comment naviguer entre les destinations de votre application.
  • Vous comprenez le cycle de vie des activités et des fragments.
  • Comment utiliser les objets ViewModel dans votre application.
  • Comment créer des objets ViewModel à l'aide de l'interface ViewModelProvider.Factory.

Points abordés

  • Ce qui rend les objets LiveData utiles.
  • Comment ajouter LiveData aux données stockées dans un ViewModel.
  • Quand et comment utiliser MutableLiveData.
  • Comment ajouter des méthodes d'observation pour voir les modifications effectuées dans LiveData..
  • Comment encapsuler LiveData à l'aide d'une propriété de support.
  • Comment communiquer entre un contrôleur d'UI et son ViewModel correspondant.

Objectifs de l'atelier

  • Utilisez LiveData pour le mot et le score dans l'application GuessTheWord.
  • Ajoutez des observateurs qui remarquent quand le mot ou le score changent.
  • Mettez à jour les vues de texte qui affichent les valeurs modifiées.
  • Utilisez le modèle d'observateur LiveData pour ajouter un événement de fin de partie.
  • Implémentez le bouton Play Again (Rejouer).

Dans les ateliers de programmation de la leçon 5, vous développez l'application GuessTheWord, en commençant par le code de démarrage. GuessTheWord est un jeu de charades à deux joueurs, dans lequel les joueurs collaborent pour obtenir le meilleur score possible.

Le premier joueur regarde les mots dans l'application et mime chacun d'eux à tour de rôle, en veillant à ne pas les montrer au deuxième joueur. Le deuxième joueur essaie de deviner le mot.

Pour jouer, le premier joueur ouvre l'application sur l'appareil et voit un mot, par exemple "guitare", comme indiqué sur la capture d'écran ci-dessous.

Le premier joueur mime le mot, en veillant à ne pas le prononcer.

  • Lorsque le deuxième joueur devine le mot, le premier joueur appuie sur le bouton OK, ce qui incrémente le compteur et affiche le mot suivant.
  • Si le deuxième joueur ne parvient pas à deviner le mot, le premier joueur appuie sur le bouton Passer, ce qui diminue le nombre de mots d'un et passe au mot suivant.
  • Pour mettre fin à la partie, appuyez sur le bouton End Game (Mettre fin à la partie). (Cette fonctionnalité n'est pas incluse dans le code de démarrage du premier atelier de programmation de la série.)

Dans cet atelier de programmation, vous allez améliorer l'application GuessTheWord en ajoutant un événement pour mettre fin à la partie lorsque l'utilisateur a parcouru tous les mots de l'application. Vous allez également ajouter un bouton Rejouer dans le fragment de score pour que l'utilisateur puisse rejouer.

Écran titre

Écran de jeu

Écran de score

Dans cette tâche, vous allez localiser et exécuter le code de démarrage de cet atelier de programmation. Vous pouvez utiliser l'application GuessTheWord que vous avez créée dans l'atelier de programmation précédent comme code de démarrage, ou télécharger une application de démarrage.

  1. (Facultatif) Si vous n'utilisez pas votre code de l'atelier de programmation précédent, téléchargez le code de démarrage pour cet atelier de programmation. Décompressez le code, puis ouvrez le projet dans Android Studio.
  2. Exécutez l'application et jouez.
  3. Notez que le bouton Ignorer affiche le mot suivant et diminue le score de un, tandis que le bouton OK affiche le mot suivant et augmente le score de un. Le bouton End Game (Terminer la partie) met fin à la partie.

LiveData est une classe de conteneur de données observable, sensible au cycle de vie. Par exemple, vous pouvez encapsuler un LiveData autour du score actuel dans l'application GuessTheWord. Dans cet atelier de programmation, vous découvrirez plusieurs caractéristiques de LiveData :

  • LiveData est une classe observable, ce qui signifie qu'un observateur est averti en cas de modification des données détenues par l'objet LiveData.
  • LiveData contient des données ; LiveData est un wrapper qui peut être utilisé avec n'importe quelle donnée.
  • LiveData tient compte du cycle de vie, ce qui signifie qu'il ne met à jour que les observateurs dont l'état du cycle de vie est actif, comme STARTED ou RESUMED.

Dans cette tâche, vous allez apprendre à encapsuler n'importe quel type de données dans des objets LiveData en convertissant les données de score et de mot actuels dans GameViewModel en LiveData. Dans une tâche ultérieure, vous ajouterez un observateur à ces objets LiveData et vous apprendrez à observer LiveData.

Étape 1 : Modifiez le score et le mot pour utiliser LiveData

  1. Sous le package screens/game, ouvrez le fichier GameViewModel.
  2. Remplacez le type des variables score et word par MutableLiveData.

    MutableLiveData est un LiveData dont la valeur peut être modifiée. MutableLiveData est une classe générique. Vous devez donc spécifier le type de données qu'elle contient.
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()
  1. Dans GameViewModel, à l'intérieur du bloc init, initialisez score et word. Pour modifier la valeur d'une variable LiveData, vous utilisez la méthode setValue() sur la variable. En langage Kotlin, vous pouvez appeler setValue() à l'aide de la propriété value.
init {

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

Étape 2 : Mettez à jour la référence de l'objet LiveData

Les variables score et word sont désormais de type LiveData. Dans cette étape, vous modifiez les références à ces variables à l'aide de la propriété value.

  1. Dans GameViewModel, dans la méthode onSkip(), remplacez score par score.value. Notez l'erreur indiquant que score est peut-être null. Vous corrigerez cette erreur ensuite.
  2. Pour résoudre l'erreur, ajoutez une vérification null à score.value dans onSkip(). Appelez ensuite la fonction minus() sur score, qui effectue la soustraction avec null-safety.
fun onSkip() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.minus(1)
   }
   nextWord()
}
  1. Mettez à jour la méthode onCorrect() de la même manière : ajoutez une vérification null à la variable score et utilisez la fonction plus().
fun onCorrect() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.plus(1)
   }
   nextWord()
}
  1. Dans GameViewModel, dans la méthode nextWord(), remplacez la référence word par word.value.
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       word.value = wordList.removeAt(0)
   }
}
  1. Dans GameFragment, dans la méthode updateWordText(), remplacez la référence viewModel.word par viewModel.word.value..
/** Methods for updating the UI **/
private fun updateWordText() {
   binding.wordText.text = viewModel.word.value
}
  1. Dans GameFragment, dans la méthode updateScoreText(), remplacez la référence à viewModel.score par viewModel.score.value..
private fun updateScoreText() {
   binding.scoreText.text = viewModel.score.value.toString()
}
  1. Dans GameFragment, dans la méthode gameFinished(), remplacez la référence à viewModel.score par viewModel.score.value. Ajoutez le contrôle de sécurité null requis.
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. Assurez-vous que votre code ne comporte pas d'erreurs. Compilez et exécutez votre application. Elle devrait fonctionner comme avant.

Cette tâche est étroitement liée à la précédente, dans laquelle vous avez converti les données de score et de mots en objets LiveData. Dans cette tâche, vous allez associer des objets Observer à ces objets LiveData.

  1. Dans GameFragment,, à l'intérieur de la méthode onCreateView(), associez un objet Observer à l'objet LiveData pour le score actuel, viewModel.score. Utilisez la méthode observe() et placez le code après l'initialisation de viewModel. Utilisez une expression lambda pour simplifier le code. (Une expression lambda est une fonction anonyme non déclarée, mais transmise immédiatement en tant qu'expression.)
viewModel.score.observe(this, Observer { newScore ->
})

Résolvez la référence à Observer. Pour ce faire, cliquez sur Observer, appuyez sur Alt+Enter (Option+Enter sur Mac), puis importez androidx.lifecycle.Observer.

  1. L'observateur que vous venez de créer reçoit un événement lorsque les données détenues par l'objet LiveData observé changent. Dans l'observateur, mettez à jour le score TextView avec le nouveau score.
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})
  1. Associez un objet Observer à l'objet LiveData du mot actuel. Procédez de la même manière que pour associer un objet Observer au score actuel.
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
   binding.wordText.text = newWord
})

Lorsque la valeur de score ou de word change, le score ou le word affiché à l'écran est désormais mis à jour automatiquement.

  1. Dans GameFragment, supprimez les méthodes updateWordText() et updateScoreText(), ainsi que toutes les références s'y rapportant. Vous n'en avez plus besoin, car les vues de texte sont mises à jour par les méthodes d'observateur LiveData.
  2. Exécutez votre application. Votre jeu devrait fonctionner exactement comme auparavant, mais il utilise désormais les observateurs LiveData et LiveData.

L'encapsulation permet de restreindre l'accès direct à certains champs d'un objet. Lorsque vous encapsulez un objet, vous exposez un ensemble de méthodes publiques qui modifient les champs internes privés. L'encapsulation vous permet de contrôler la façon dont les autres classes manipulent ces champs internes.

Dans votre code actuel, n'importe quelle classe externe peut modifier les variables score et word à l'aide de la propriété value, par exemple en utilisant viewModel.score.value. Cela n'a peut-être pas d'importance dans l'application que vous développez dans cet atelier de programmation, mais dans une application de production, vous souhaitez contrôler les données des objets ViewModel.

Seul le ViewModel doit modifier les données de votre application. Toutefois, les contrôleurs d'UI doivent lire les données. Les champs de données ne peuvent donc pas être entièrement privés. Pour encapsuler les données de votre application, vous utilisez les objets MutableLiveData et LiveData.

MutableLiveData contre LiveData :

  • Comme son nom l'indique, les données d'un objet MutableLiveData peuvent être modifiées. Dans le ViewModel, les données doivent être modifiables. Elles utilisent donc MutableLiveData.
  • Les données d'un objet LiveData peuvent être lues, mais pas modifiées. En dehors de ViewModel, les données doivent être lisibles, mais pas modifiables. Elles doivent donc être présentées comme LiveData.

Pour mettre en œuvre cette stratégie, vous utilisez une propriété de support Kotlin. Une propriété de support vous permet de renvoyer un élément d'un getter qui n'est pas l'objet exact. Dans cette tâche, vous allez implémenter une propriété de sauvegarde pour les objets score et word dans l'application GuessTheWord.

Ajouter une propriété de support au score et au mot

  1. Dans GameViewModel, définissez l'objet score actuel sur private.
  2. Pour respecter la convention d'attribution de noms utilisée dans les propriétés de support, remplacez score par _score. La propriété _score est désormais la version modifiable du score du jeu, à utiliser en interne.
  3. Créez une version publique du type LiveData, appelée score.
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
  1. Une erreur d'initialisation s'affiche. Cette erreur se produit, car dans GameFragment, score est une référence LiveData et score ne peut plus accéder à son setter. Pour en savoir plus sur les getters et les setters en Kotlin, consultez Getters et setters.

    Pour résoudre l'erreur, remplacez la méthode get() pour l'objet score dans GameViewModel et renvoyez la propriété de sauvegarde, _score.
val score: LiveData<Int>
   get() = _score
  1. Dans GameViewModel, remplacez les références de score par sa version interne modifiable, _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. Renommez l'objet word en _word et ajoutez-lui une propriété de support, comme vous l'avez fait pour l'objet 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)
   }
}

Bravo, vous avez encapsulé les objets LiveData word et score.

Votre application actuelle accède à l'écran du score lorsque l'utilisateur appuie sur le bouton End Game (Fin de partie). Vous souhaitez également que l'application accède à l'écran des scores lorsque les joueurs ont parcouru tous les mots. Une fois que les joueurs ont terminé avec le dernier mot, vous voulez que le jeu se termine automatiquement afin que l'utilisateur n'ait pas à appuyer sur le bouton.

Pour implémenter cette fonctionnalité, vous avez besoin qu'un événement soit déclenché et communiqué au fragment à partir de ViewModel lorsque tous les mots ont été affichés. Pour ce faire, vous utilisez le modèle d'observateur LiveData pour modéliser un événement de fin de partie.

Le modèle d'observateur

Le modèle d'observateur est un modèle de conception logicielle. Il spécifie la communication entre les objets : un observable (le "sujet" de l'observation) et les observateurs. Un observable est un objet qui informe les observateurs des changements d'état.

Dans le cas de LiveData dans cette application, l'observable (sujet) est l'objet LiveData, et les observateurs sont les méthodes des contrôleurs d'UI, tels que les fragments. Un changement d'état se produit chaque fois que les données encapsulées dans LiveData changent. Les classes LiveData sont essentielles pour communiquer du ViewModel au fragment.

Étape 1 : Utilisez LiveData pour détecter un événement de fin de partie

Dans cette tâche, vous allez utiliser le modèle d'observateur LiveData pour modéliser un événement de fin de partie.

  1. Dans GameViewModel, créez un objet MutableLiveData Boolean appelé _eventGameFinish. Cet objet contiendra l'événement de fin de partie.
  2. Après avoir initialisé l'objet _eventGameFinish, créez et initialisez une propriété de sauvegarde appelée eventGameFinish.
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
   get() = _eventGameFinish
  1. Dans GameViewModel, ajoutez une méthode onGameFinish(). Dans la méthode, définissez l'événement de fin de partie, eventGameFinish, sur true.
/** Method for the game completed event **/
fun onGameFinish() {
   _eventGameFinish.value = true
}
  1. Dans GameViewModel, à l'intérieur de la méthode nextWord(), mettez fin au jeu si la liste de mots est vide.
private fun nextWord() {
   if (wordList.isEmpty()) {
       onGameFinish()
   } else {
       //Select and remove a _word from the list
       _word.value = wordList.removeAt(0)
   }
}
  1. Dans GameFragment, à l'intérieur de onCreateView(), après avoir initialisé viewModel, associez un observateur à eventGameFinish. Utilisez la méthode observe(). Dans la fonction lambda, appelez la méthode gameFinished().
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
   if (hasFinished) gameFinished()
})
  1. Exécutez votre application, jouez et parcourez tous les mots. L'application accède automatiquement à l'écran du score au lieu de rester dans le fragment de jeu jusqu'à ce que vous appuyiez sur Fin de partie.

    Une fois la liste de mots vide, eventGameFinish est défini, la méthode d'observation associée dans le fragment de jeu est appelée et l'application accède au fragment d'écran.
  2. Le code que vous avez ajouté a introduit un problème de cycle de vie. Pour comprendre le problème, dans la classe GameFragment, mettez en commentaire le code de navigation dans la méthode gameFinished(). Veillez à conserver le message Toast dans la méthode.
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. Exécutez votre application, jouez et parcourez tous les mots. Un toast indiquant "La partie vient de se terminer" s'affiche brièvement en bas de l'écran de jeu, ce qui est le comportement attendu.

Faites maintenant pivoter l'appareil ou l'émulateur. Le toast s'affiche à nouveau ! Faites pivoter l'appareil plusieurs fois de plus. Vous devriez voir le message à chaque fois. Il s'agit d'un bug, car le toast ne devrait s'afficher qu'une seule fois, à la fin de la partie. Le toast ne doit pas s'afficher chaque fois que le fragment est recréé. Vous résoudrez ce problème dans la prochaine tâche.

Étape 2 : Réinitialisez l'événement "game-finished"

En général, LiveData ne transmet des mises à jour aux observateurs que si les données sont modifiées. Il existe une exception à ce comportement : les observateurs reçoivent également des mises à jour lorsqu'ils passent d'un état inactif à un état actif.

C'est pourquoi le toast de fin de partie est déclenché à plusieurs reprises dans votre application. Lorsque le fragment de jeu est recréé après une rotation de l'écran, il passe d'un état inactif à un état actif. L'observateur du fragment est reconnecté au ViewModel existant et reçoit les données actuelles. La méthode gameFinished() est à nouveau déclenchée et le toast s'affiche.

Dans cette tâche, vous allez résoudre ce problème et n'afficher le toast qu'une seule fois en réinitialisant l'indicateur eventGameFinish dans GameViewModel.

  1. Dans GameViewModel, ajoutez une méthode onGameFinishComplete() pour réinitialiser l'événement de fin de partie, _eventGameFinish.
/** Method for the game completed event **/

fun onGameFinishComplete() {
   _eventGameFinish.value = false
}
  1. Dans GameFragment, à la fin de gameFinished(), appelez onGameFinishComplete() sur l'objet viewModel. (Pour l'instant, laissez le code de navigation en commentaire dans gameFinished().)
private fun gameFinished() {
   ...
   viewModel.onGameFinishComplete()
}
  1. Exécutez l'application et jouez. Parcourez tous les mots, puis modifiez l'orientation de l'écran de l'appareil. Le toast ne s'affiche qu'une seule fois.
  2. Dans GameFragment, à l'intérieur de la méthode gameFinished(), supprimez la mise en commentaire du code de navigation.

    Pour supprimer la mise en commentaire dans Android Studio, sélectionnez les lignes commentées et appuyez sur Control+/ (Command+/ sur 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()
}

Importez androidx.navigation.fragment.NavHostFragment.findNavController, si Android Studio vous le demande.

  1. Exécutez l'application et jouez. Assurez-vous que l'application accède automatiquement à l'écran du score final après que vous avez parcouru tous les mots.

Bien joué ! Votre application utilise LiveData pour déclencher un événement de fin de partie afin de communiquer du GameViewModel au fragment de jeu que la liste de mots est vide. Le fragment de jeu accède ensuite au fragment de score.

Dans cette tâche, vous allez remplacer le score par un objet LiveData dans ScoreViewModel et y associer un observateur. Cette tâche est semblable à celle que vous avez effectuée lorsque vous avez ajouté LiveData à GameViewModel.

Vous apportez ces modifications à ScoreViewModel pour que toutes les données de votre application utilisent LiveData.

  1. Dans ScoreViewModel, remplacez le type de la variable score par MutableLiveData. Renommez-le par convention en _score et ajoutez une propriété de support.
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
   get() = _score
  1. Dans ScoreViewModel, à l'intérieur du bloc init, initialisez _score. Vous pouvez supprimer ou laisser le journal dans le bloc init comme vous le souhaitez.
init {
   _score.value = finalScore
}
  1. Dans ScoreFragment, à l'intérieur de onCreateView(), après avoir initialisé viewModel, associez un observateur à l'objet LiveData du score. Dans l'expression lambda, définissez la valeur du score sur l'affichage de texte du score. Supprimez le code qui attribue directement la valeur du score à la vue de texte à partir de ViewModel.

Code à ajouter :

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

Code à supprimer :

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

Lorsqu'Android Studio vous le demande, importez androidx.lifecycle.Observer.

  1. Exécutez votre application et jouez. L'application devrait fonctionner comme avant, mais elle utilise désormais LiveData et un observateur pour mettre à jour le score.

Dans cette tâche, vous allez ajouter un bouton Rejouer à l'écran du score et implémenter son écouteur de clics à l'aide d'un événement LiveData. Le bouton déclenche un événement permettant de passer de l'écran de score à l'écran de jeu.

Le code de démarrage de l'application inclut le bouton Rejouer, mais il est masqué.

  1. Dans res/layout/score_fragment.xml, pour le bouton play_again_button, remplacez la valeur de l'attribut visibility par visible.
<Button
   android:id="@+id/play_again_button"
...
   android:visibility="visible"
 />
  1. Dans ScoreViewModel, ajoutez un objet LiveData pour contenir un Boolean appelé _eventPlayAgain. Cet objet permet d'enregistrer l'événement LiveData pour passer de l'écran du score à l'écran du jeu.
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
   get() = _eventPlayAgain
  1. Dans ScoreViewModel, définissez des méthodes pour définir et réinitialiser l'événement, _eventPlayAgain.
fun onPlayAgain() {
   _eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
   _eventPlayAgain.value = false
}
  1. Dans ScoreFragment, ajoutez un observateur pour eventPlayAgain. Placez le code à la fin de onCreateView(), avant l'instruction return. Dans l'expression lambda, revenez à l'écran du jeu et réinitialisez eventPlayAgain.
// Navigates back to game when button is pressed
viewModel.eventPlayAgain.observe(this, Observer { playAgain ->
   if (playAgain) {
      findNavController().navigate(ScoreFragmentDirections.actionRestart())
       viewModel.onPlayAgainComplete()
   }
})

Importez androidx.navigation.fragment.findNavController lorsqu'Android Studio vous le demande.

  1. Dans ScoreFragment, à l'intérieur de onCreateView(), ajoutez un écouteur de clics au bouton PlayAgain (Rejouer) et appelez viewModel.onPlayAgain().
binding.playAgainButton.setOnClickListener {  viewModel.onPlayAgain()  }
  1. Exécutez votre application et jouez. Une fois la partie terminée, l'écran du score affiche le score final et le bouton Rejouer. Appuyez sur le bouton PlayAgain (Rejouer). L'application vous redirige vers l'écran du jeu pour que vous puissiez rejouer.

Bravo ! Vous avez modifié l'architecture de votre application pour utiliser des objets LiveData dans ViewModel et vous avez associé des observateurs aux objets LiveData. LiveData avertit les objets observateurs lorsque la valeur détenue par LiveData change.

Projet Android Studio : GuessTheWord

LiveData

  • LiveData est une classe de conteneur de données observable, sensible au cycle de vie, qui fait partie des composants d'architecture Android.
  • Vous pouvez utiliser LiveData pour permettre à votre UI de se mettre à jour automatiquement lorsque les données sont modifiées.
  • LiveData est une classe observable, ce qui signifie qu'un observateur tel qu'une activité ou un fragment peut être averti en cas de modification des données détenues par l'objet LiveData.
  • LiveData contient des données ; il s'agit d'un wrapper qui peut être utilisé avec n'importe quelle donnée.
  • LiveData tient compte du cycle de vie, ce qui signifie qu'il ne met à jour que les observateurs dont l'état du cycle de vie est actif, comme STARTED ou RESUMED.

Pour ajouter LiveData

  • Remplacez le type des variables de données dans ViewModel par LiveData ou MutableLiveData.

MutableLiveData est un objet LiveData dont la valeur peut être modifiée. MutableLiveData est une classe générique. Vous devez donc spécifier le type de données qu'elle contient.

  • Pour modifier la valeur des données détenues par LiveData, utilisez la méthode setValue() sur la variable LiveData.

Pour encapsuler LiveData

  • Le LiveData à l'intérieur du ViewModel doit être modifiable. En dehors de ViewModel, LiveData doit être lisible. Pour ce faire, vous pouvez utiliser une propriété de support Kotlin.
  • Une propriété de support Kotlin vous permet de renvoyer un élément d'un getter qui n'est pas l'objet exact.
  • Pour encapsuler le LiveData, utilisez private MutableLiveData à l'intérieur du ViewModel et renvoyez une propriété de sauvegarde LiveData en dehors du ViewModel.

Observable LiveData

  • LiveData suit un modèle d'observateur. L'"observable" est l'objet LiveData, et les observateurs sont les méthodes des contrôleurs d'UI, comme les fragments. Chaque fois que les données encapsulées dans LiveData changent, les méthodes d'observation des contrôleurs d'UI sont averties.
  • Pour rendre LiveData observable, associez un objet observateur à la référence LiveData dans les observateurs (tels que les activités et les fragments) à l'aide de la méthode observe().
  • Ce modèle d'observateur LiveData peut être utilisé pour communiquer depuis ViewModel vers les contrôleurs d'UI.

Cours Udacity :

Documentation pour les développeurs Android :

Autre :

Cette section répertorie les devoirs possibles pour les élèves qui suivent cet atelier de programmation dans le cadre d'un cours animé par un enseignant. Il revient à l'enseignant d'effectuer les opérations suivantes :

  • Attribuer des devoirs si nécessaire
  • Indiquer aux élèves comment rendre leurs devoirs
  • Noter les devoirs

Les enseignants peuvent utiliser ces suggestions autant qu'ils le souhaitent, et ne doivent pas hésiter à attribuer d'autres devoirs aux élèves s'ils le jugent nécessaire.

Si vous suivez cet atelier de programmation par vous-même, n'hésitez pas à utiliser ces devoirs pour tester vos connaissances.

Répondre aux questions suivantes

Question 1

Comment encapsuler le LiveData stocké dans un ViewModel pour que les objets externes puissent lire les données sans pouvoir les mettre à jour ?

  • Dans l'objet ViewModel, remplacez le type de données par private LiveData. Utilisez une propriété de support pour exposer des données en lecture seule du type MutableLiveData.
  • Dans l'objet ViewModel, remplacez le type de données par private MutableLiveData. Utilisez une propriété de support pour exposer des données en lecture seule du type LiveData.
  • Dans le contrôleur d'interface utilisateur, remplacez le type de données par private MutableLiveData. Utilisez une propriété de support pour exposer des données en lecture seule du type LiveData.
  • Dans l'objet ViewModel, remplacez le type de données par LiveData. Utilisez une propriété de support pour exposer des données en lecture seule du type LiveData.

Question 2

Parmi les états suivants, lequel permet à LiveData de mettre à jour un contrôleur d'interface utilisateur (un fragment, par exemple) ?

  • A repris
  • En arrière-plan
  • Suspendue
  • Arrêté

Question 3

Dans le modèle d'observateur LiveData, quel est l'élément observable (ce qui est observé) ?

  • La méthode de l'observateur
  • Les données d'un objet LiveData
  • Le contrôleur d'interface utilisateur
  • L'objet ViewModel

Passez à la leçon suivante : 5.3 : Liaison de données avec ViewModel et LiveData

Pour obtenir des liens vers d'autres ateliers de programmation de ce cours, consultez la page de destination des ateliers de programmation Principes de base d'Android en Kotlin.