Cet atelier de programmation fait partie du cours Android Kotlin Fundamentals. Vous tirerez le meilleur parti de ce cours si vous suivez les ateliers de programmation dans l'ordre. Tous les ateliers de programmation du cours sont répertoriés sur la page de destination des ateliers de programmation Android Kotlin Fundamentals.
Introduction
Dans les précédents ateliers de programmation de cette leçon, vous avez amélioré le code de l'application GuessTheWord. L'application utilise désormais des objets ViewModel
. Les données de l'application survivent donc aux modifications de la configuration de l'appareil, telles que les rotations d'écran et les modifications apportées à la disponibilité du clavier. Vous avez également ajouté le LiveData
observable, afin que les vues soient automatiquement averties lorsque les données observées changent.
Dans cet atelier de programmation, vous continuez à travailler avec l'application GuessTheWord. Vous liez les vues aux classes ViewModel
de l'application pour que les vues de votre mise en page communiquent directement avec les objets ViewModel
. Jusqu'à présent, les vues étaient indirectement transmises aux éléments ViewModel
via les fragments d'application. Après avoir intégré la liaison de données avec les objets ViewModel
, vous n'avez plus besoin de gestionnaires de clics dans les fragments de l'application. Vous les supprimez donc.
Vous allez également modifier l'application GuessTheWord pour utiliser LiveData
comme source de liaison de données afin d'informer l'UI des modifications apportées aux données, sans utiliser les méthodes d'observation LiveData
.
Ce que vous devez déjà savoir
- Créer des applications Android de base en Kotlin
- Fonctionnement des cycles de vie des activités et des fragments.
- Comment utiliser des objets
ViewModel
dans votre application - Comment stocker des données en utilisant
LiveData
dans uneViewModel
- Découvrez comment ajouter des méthodes d'observation afin d'observer les modifications dans les données
LiveData
.
Points abordés
- Utiliser des éléments de la bibliothèque de liaisons de données
- Intégrer
ViewModel
avec une liaison de données - Intégrer
LiveData
avec une liaison de données - Utiliser des liaisons d'écouteur pour remplacer les écouteurs de clics dans un fragment.
- Comment ajouter une mise en forme de chaîne à des expressions de liaison de données.
Objectifs de l'atelier
- Les vues des mises en page GuessTheWord communiquent indirectement avec des objets
ViewModel
, en utilisant des contrôleurs d'interface utilisateur (fragments) pour transmettre des informations. Dans cet atelier de programmation, vous associez les vues de l'application aux objetsViewModel
pour qu'elles communiquent directement avec les objetsViewModel
. - Vous modifiez l'application pour utiliser
LiveData
comme source de liaison de données. Après cette modification, les objetsLiveData
notifient l'interface utilisateur des modifications apportées aux données, et les méthodes d'observationLiveData
ne sont plus nécessaires.
Dans les ateliers de programmation de la leçon 5, vous allez développer l'application GuessTheWord en commençant par le code de démarrage. GuessTheWord est un jeu de charades à deux joueurs, où les joueurs collaborent pour obtenir le meilleur score possible.
Le premier joueur analyse les mots dans l'application et les joue tous à tour de rôle. Veillez donc à ne pas afficher le mot au deuxième joueur. Le deuxième joueur essaie de deviner le mot.
Pour lancer ce jeu, le premier joueur ouvre l'application sur l'appareil et voit un mot, par exemple "guitare", comme illustré dans la capture d'écran ci-dessous.
Le premier joueur joue le mot, en prenant soin de ne pas le prononcer.
- Lorsque le deuxième joueur essaie de deviner le mot, le premier appuie sur le bouton OK, ce qui augmente le nombre de points et affiche le mot suivant.
- S'il ne parvient pas à deviner le mot, le premier joueur appuie sur le bouton Ignorer, ce qui diminue le nombre de fois jusqu'à l'affichage du mot suivant.
- Pour terminer la partie, appuyez sur le bouton Terminer le jeu. (Cette fonctionnalité n'est pas disponible dans le code de démarrage du premier atelier de programmation de cette série.)
Dans cet atelier de programmation, vous allez améliorer l'application GuessTheWord en intégrant la liaison de données à LiveData
dans les objets ViewModel
. Cela permet d'automatiser la communication entre les vues dans la mise en page et les objets ViewModel
, et de simplifier le code en utilisant LiveData
.
É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. Vous pouvez également en télécharger une.
- (Facultatif) Si vous n'utilisez pas le code de l'atelier de programmation précédent, téléchargez-le. Décompressez le code, puis ouvrez le projet dans Android Studio.
- Exécutez l'application et jouez au jeu.
- Notez que le bouton OK affiche le mot suivant et augmente le score de 1, tandis que le bouton Ignorer affiche le mot suivant et diminue le score de 1. Le bouton Terminer le jeu met fin au jeu.
- Parcourez tous les mots et notez que l'application accède automatiquement à l'écran de score.
Dans un atelier de programmation précédent, vous avez utilisé la liaison de données pour accéder aux vues dans l'application GuessTheWord en toute sécurité. Mais la véritable force de ce composant est de faire ce que suggère le nom: lier des données directement aux objets de la vue dans votre application.
Architecture d'application actuelle
Dans votre application, les vues sont définies dans la mise en page XML, et les données correspondantes sont conservées dans les objets ViewModel
. Entre chaque vue et les ViewModel
correspondantes, un contrôleur d'interface utilisateur agit comme un relais entre elles.
Exemple :
- Le bouton OK est défini en tant que vue
Button
dans le fichier de mise en pagegame_fragment.xml
. - Lorsque l'utilisateur appuie sur le bouton OK, un écouteur de clics du fragment
GameFragment
appelle l'écouteur de clics correspondant dansGameViewModel
. - Le score est mis à jour dans
GameViewModel
.
La vue Button
et la GameViewModel
ne communiquent pas directement. Ils doivent utiliser l'écouteur de clics GameFragment
.
ViewModel transmis dans la liaison de données
Il serait plus simple si les vues de la mise en page communiquent directement avec les données des objets ViewModel
, sans utiliser les contrôleurs de l'interface utilisateur comme intermédiaires.
Les objets ViewModel
contiennent toutes les données de l'interface utilisateur de l'application GuessTheWord. En transmettant des objets ViewModel
à la liaison de données, vous pouvez automatiser certaines des communications entre les vues et les objets ViewModel
.
Dans cette tâche, vous allez associer les classes GameViewModel
et ScoreViewModel
à leurs mises en page XML correspondantes. Vous allez également configurer des liaisons d'écouteur pour gérer les événements de clic.
Étape 1: Ajoutez une liaison de données pour GameViewModel
Dans cette étape, vous allez associer GameViewModel
au fichier de mise en page correspondant (game_fragment.xml
).
- Dans le fichier
game_fragment.xml
, ajoutez une variable de liaison de données de typeGameViewModel
. Si vous rencontrez des erreurs dans Android Studio, nettoyez et recréez le projet.
<layout ...>
<data>
<variable
name="gameViewModel"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
<androidx.constraintlayout...
- Dans le fichier
GameFragment
, transmettezGameViewModel
à la liaison de données.
Pour ce faire, attribuezviewModel
à la variablebinding.gameViewModel
que vous avez déclarée à l'étape précédente. Placez ce code dansonCreateView()
, après l'initialisation deviewModel
. Si vous rencontrez des erreurs dans Android Studio, nettoyez et recréez le projet.
// Set the viewmodel for databinding - this allows the bound layout access
// to all the data in the ViewModel
binding.gameViewModel = viewModel
Étape 2: Utilisez des liaisons d'écouteur pour la gestion des événements
Les liaisons d'écouteur sont des expressions de liaison qui s'exécutent lorsque des événements tels que onClick()
, onZoomIn()
ou onZoomOut()
sont déclenchés. Les liaisons d'écouteur sont écrites sous forme d'expressions lambda.
La liaison de données crée un écouteur et définit l'écouteur sur la vue. Lorsque l'événement écouté est écouté, l'écouteur évalue l'expression lambda. Les liaisons d'écouteur fonctionnent avec le plug-in Android Gradle 2.0 ou version ultérieure. Pour en savoir plus, consultez l'article Mises en page et expressions liées à la liaison.
Au cours de cette étape, vous allez remplacer les écouteurs de clics du fichier GameFragment
par des liaisons d'écouteurs dans le fichier game_fragment.xml
.
- Dans
game_fragment.xml
, ajoutez l'attributonClick
auskip_button
. Définissez une expression de liaison et appelez la méthodeonSkip()
dansGameViewModel
. Cette expression de liaison est appelée liaison d'écouteur.
<Button
android:id="@+id/skip_button"
...
android:onClick="@{() -> gameViewModel.onSkip()}"
... />
- De même, liez l'événement de clic de la
correct_button
à la méthodeonCorrect
()
dans leGameViewModel
.
<Button
android:id="@+id/correct_button"
...
android:onClick="@{() -> gameViewModel.onCorrect()}"
... />
- Associez l'événement de clic de la
end_game_button
à la méthodeonGameFinish
()
dans leGameViewModel
.
<Button
android:id="@+id/end_game_button"
...
android:onClick="@{() -> gameViewModel.onGameFinish()}"
... />
- Dans
GameFragment
, supprimez les instructions qui définissent les écouteurs de clics, ainsi que les fonctions que les écouteurs de clics appellent. Vous n'en avez plus besoin.
Code à supprimer:
binding.correctButton.setOnClickListener { onCorrect() }
binding.skipButton.setOnClickListener { onSkip() }
binding.endGameButton.setOnClickListener { onEndGame() }
/** Methods for buttons presses **/
private fun onSkip() {
viewModel.onSkip()
}
private fun onCorrect() {
viewModel.onCorrect()
}
private fun onEndGame() {
gameFinished()
}
Étape 3: Ajoutez une liaison de données pour le ScoreViewModel
Dans cette étape, vous allez associer ScoreViewModel
au fichier de mise en page correspondant (score_fragment.xml
).
- Dans le fichier
score_fragment.xml
, ajoutez une variable de liaison de typeScoreViewModel
. Cette étape est semblable à celle que vous avez suivie pourGameViewModel
ci-dessus.
<layout ...>
<data>
<variable
name="scoreViewModel"
type="com.example.android.guesstheword.screens.score.ScoreViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
- Dans
score_fragment.xml
, ajoutez l'attributonClick
auplay_again_button
. Définissez une liaison d'écouteur et appelez la méthodeonPlayAgain()
dansScoreViewModel
.
<Button
android:id="@+id/play_again_button"
...
android:onClick="@{() -> scoreViewModel.onPlayAgain()}"
... />
- Dans
ScoreFragment
, initialisezviewModel
dansonCreateView()
. Ensuite, initialisez la variable de liaisonbinding.scoreViewModel
.
viewModel = ...
binding.scoreViewModel = viewModel
- Dans
ScoreFragment
, supprimez le code qui définit l'écouteur de clics pourplayAgainButton
. Si Android Studio affiche une erreur, nettoyez et recréez le projet.
Code à supprimer:
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }
- Exécutez votre application. Celle-ci devrait fonctionner comme avant, mais les vues du bouton doivent désormais communiquer directement avec les objets
ViewModel
. Les vues ne communiquent plus via les gestionnaires de clics sur le bouton dansScoreFragment
.
Résoudre les messages d'erreur liés à la liaison de données
Lorsqu'une application utilise la liaison de données, le processus de compilation génère des classes intermédiaires qui sont utilisées pour la liaison de données. Une application peut rencontrer des erreurs qu'Android Studio ne détecte pas tant que vous ne l'avez pas compilée. De ce fait, aucun avertissement ou code rouge ne s'affiche lorsque vous écrivez le code. Toutefois, au moment de la compilation, vous obtenez des erreurs cryptées provenant des classes intermédiaires générées.
Si vous recevez un message d'erreur crypté:
- Lisez attentivement le message dans le volet Build d'Android Studio. Si vous constatez qu'un emplacement se termine par
databinding
, une erreur s'est produite au niveau de la liaison de données. - Dans le fichier XML de mise en page, recherchez les erreurs d'attributs
onClick
qui utilisent la liaison de données. Recherchez la fonction appelée par l'expression lambda et assurez-vous qu'elle existe. - Dans la section
<data>
du code XML, vérifiez l'orthographe de la variable data-binding.
Par exemple, notez la faute d'orthographe dans le nom de la fonction onCorrect()
dans la valeur d'attribut suivante:
android:onClick="@{() -> gameViewModel.onCorrectx()}"
Notez également l'orthographe de gameViewModel
dans la section <data>
du fichier XML :
<data>
<variable
name="gameViewModelx"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
Android Studio ne détecte pas ces erreurs tant que vous n'avez pas compilé l'application. Le compilateur affiche ensuite un message d'erreur semblable à celui-ci :
error: cannot find symbol import com.example.android.guesstheword.databinding.GameFragmentBindingImpl" symbol: class GameFragmentBindingImpl location: package com.example.android.guesstheword.databinding
La liaison de données fonctionne bien avec LiveData
qui est utilisé avec des objets ViewModel
. Maintenant que vous avez ajouté une liaison de données aux objets ViewModel
, vous pouvez intégrer LiveData
.
Dans cette tâche, vous allez modifier l'application GuessTheWord pour utiliser LiveData
comme source de liaison de données afin d'informer l'UI des modifications apportées aux données, sans avoir à utiliser les méthodes d'observation LiveData
.
Étape 1: Ajoutez le mot "LiveData" au fichier game_fragment.xml
Au cours de cette étape, vous allez lier la vue textuelle actuelle directement à l'objet LiveData
dans ViewModel
.
- Dans
game_fragment.xml
, ajoutez l'attributandroid:text
à la vue Texteword_text
.
Définissez-le sur l'objet LiveData
, word
à partir de GameViewModel
, en utilisant la variable de liaison gameViewModel
.
<TextView
android:id="@+id/word_text"
...
android:text="@{gameViewModel.word}"
... />
Notez que vous n'avez pas besoin d'utiliser word.value
. Vous pouvez utiliser l'objet LiveData
réel. L'objet LiveData
affiche la valeur actuelle de word
. Si la valeur de word
est nulle, l'objet LiveData
affiche une chaîne vide.
- Dans
GameFragment
, dansonCreateView()
, après avoir initialiségameViewModel
, définissez l'activité actuelle en tant que propriétaire du cycle de vie de la variablebinding
. Cela définit le champ d'application de l'objetLiveData
ci-dessus, qui permet à l'objet de mettre à jour automatiquement les vues dans la mise en pagegame_fragment.xml
.
binding.gameViewModel = ...
// Specify the current activity as the lifecycle owner of the binding.
// This is used so that the binding can observe LiveData updates
binding.lifecycleOwner = this
- Dans
GameFragment
, supprimez l'observateur pour leLiveData
word
.
Code à supprimer:
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
binding.wordText.text = newWord
})
- Exécutez votre application et jouez au jeu. Le mot actuel est en cours de mise à jour sans méthode d'observation dans le contrôleur d'interface utilisateur.
Étape 2: Ajoutez LiveData au fichier score_fragment.xml
Au cours de cette étape, vous allez associer LiveData
score
à la vue textuelle du score dans le fragment de score.
- Dans
score_fragment.xml
, ajoutez l'attributandroid:text
à la vue textuelle du score. Attribuez la valeurscoreViewModel.score
à l'attributtext
. Commescore
est un entier, convertissez-le en chaîne à l'aide deString.valueOf()
.
<TextView
android:id="@+id/score_text"
...
android:text="@{String.valueOf(scoreViewModel.score)}"
... />
- Dans
ScoreFragment
, après avoir initialiséscoreViewModel
, définissez l'activité actuelle en tant que propriétaire du cycle de vie de la variablebinding
.
binding.scoreViewModel = ...
// Specify the current activity as the lifecycle owner of the binding.
// This is used so that the binding can observe LiveData updates
binding.lifecycleOwner = this
- Dans
ScoreFragment
, supprimez l'observateur de l'objetscore
.
Code à supprimer:
// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
- Exécutez votre application et jouez au jeu. Notez que le score dans le fragment de score est affiché correctement, sans observateur dans le fragment de score.
Étape 3: Ajoutez une mise en forme de chaîne avec la liaison de données
Dans la mise en page, vous pouvez ajouter une mise en forme de chaîne avec une liaison de données. Dans cette tâche, vous allez formater le mot actuel pour y ajouter des guillemets. Vous devez également formater la chaîne de score comme préfixe Score Score, comme illustré ci-dessous.
- Dans
string.xml
, ajoutez les chaînes suivantes, que vous utiliserez pour mettre en forme les vues textuellesword
etscore
.%s
et%d
sont les espaces réservés au mot actuel et au score actuel.
<string name="quote_format">\"%s\"</string>
<string name="score_format">Current Score: %d</string>
- Dans
game_fragment.xml
, mettez à jour l'attributtext
de la vue Texteword_text
pour utiliser la ressource de chaînequote_format
. Transmettre dansgameViewModel.word
. Le mot actuel est transmis en tant qu'argument à la chaîne de mise en forme.
<TextView
android:id="@+id/word_text"
...
android:text="@{@string/quote_format(gameViewModel.word)}"
... />
- Mettez en forme la vue textuelle de
score
de la même manière queword_text
. Dansgame_fragment.xml
, ajoutez l'attributtext
à la vue Textescore_text
. Utilisez la ressource de chaînescore_format
, qui utilise un argument numérique, représenté par l'espace réservé%d
. Transmettez l'objetLiveData
,score
, en tant qu'argument à cette chaîne de mise en forme.
<TextView
android:id="@+id/score_text"
...
android:text="@{@string/score_format(gameViewModel.score)}"
... />
- Dans la classe
GameFragment
, supprimez le code observateurscore
de la méthodeonCreateView()
.
Code à supprimer:
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
- Nettoyez, recréez et exécutez votre application, puis jouez au jeu. Notez que le mot actuel et le score sont mis en forme dans l'écran du jeu.
Félicitations ! Vous avez intégré LiveData
et ViewModel
avec la liaison de données dans votre application. Cela permet aux vues de votre mise en page de communiquer directement avec le ViewModel
, sans utiliser de gestionnaires de clics dans le fragment. Vous avez également utilisé les objets LiveData
comme source de liaison de données pour informer automatiquement l'UI des modifications apportées aux données, sans les méthodes d'observation LiveData
.
Projet Android Studio: GuessTheWord
- La bibliothèque de liaisons de données fonctionne de manière transparente avec les composants d'architecture Android, tels que
ViewModel
etLiveData
. - Les mises en page de votre application peuvent être associées aux données des composants d'architecture, ce qui vous permet déjà de gérer le cycle de vie du contrôleur d'interface et d'être informé des modifications apportées aux données.
Liaison de données ViewModel
- Vous pouvez associer un
ViewModel
à une mise en page à l'aide d'une liaison de données. - Les objets
ViewModel
contiennent les données d'interface utilisateur. En transmettant des objetsViewModel
dans la liaison de données, vous pouvez automatiser certaines des communications entre les vues et les objetsViewModel
.
Pour associer un ViewModel
à une mise en page:
- Dans le fichier de mise en page, ajoutez une variable de liaison de données de type
ViewModel
.
<data>
<variable
name="gameViewModel"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
- Dans le fichier
GameFragment
, transmettezGameViewModel
à la liaison de données.
binding.gameViewModel = viewModel
Liaisons d'écouteurs
- Les liaisons d'écouteur sont des expressions de liaison qui s'exécutent lorsque des événements de clic tels que
onClick()
sont déclenchés. - Les liaisons d'écouteur sont écrites sous forme d'expressions lambda.
- À l'aide de liaisons d'écouteur, vous remplacez les écouteurs de clics dans les contrôleurs d'interface par les liaisons d'écouteur dans le fichier de mise en page.
- La liaison de données crée un écouteur et définit l'écouteur sur la vue.
android:onClick="@{() -> gameViewModel.onSkip()}"
Ajouter LiveData à la liaison de données
- Les objets
LiveData
peuvent être utilisés comme source de liaison de données pour informer automatiquement l'UI des modifications apportées aux données. - Vous pouvez lier la vue directement à l'objet
LiveData
dans leViewModel
. LorsqueLiveData
dansViewModel
change, les vues de la mise en page peuvent être automatiquement mises à jour, sans les méthodes d'observation dans les contrôleurs de l'interface utilisateur.
android:text="@{gameViewModel.word}"
- Pour que la liaison de données
LiveData
fonctionne, définissez l'activité actuelle (contrôleur d'interface utilisateur) en tant que propriétaire du cycle de vie de la variablebinding
dans le contrôleur d'interface utilisateur.
binding.lifecycleOwner = this
Mise en forme de chaîne avec liaison de données
- La liaison de données vous permet de mettre en forme une ressource de chaîne avec des espaces réservés tels que
%s
pour les chaînes et%d
pour des entiers. - Pour mettre à jour l'attribut
text
de la vue, transmettez l'objetLiveData
en tant qu'argument à la chaîne de mise en forme.
android:text="@{@string/quote_format(gameViewModel.word)}"
Cours Udacity:
Documentation pour les développeurs Android:
Cette section répertorie les devoirs possibles pour les élèves qui effectuent cet atelier de programmation dans le cadre d'un cours animé par un enseignant. C'est à l'enseignant de procéder comme suit:
- Si nécessaire, rendez-les.
- Communiquez aux élèves comment rendre leurs devoirs.
- Notez les devoirs.
Les enseignants peuvent utiliser ces suggestions autant qu'ils le souhaitent, et ils n'ont pas besoin d'attribuer les devoirs de leur choix.
Si vous suivez vous-même cet atelier de programmation, n'hésitez pas à utiliser ces devoirs pour tester vos connaissances.
Répondez à ces questions.
Question 1
Parmi les affirmations suivantes concernant les liaisons d'écouteur, laquelle n'est pas vraie ?
- Les liaisons d'écouteur sont des expressions de liaison qui s'exécutent lorsqu'un événement se produit.
- Les liaisons d'écouteur fonctionnent avec toutes les versions du plug-in Android Gradle.
- Les liaisons d'écouteur sont écrites sous forme d'expressions lambda.
- Les liaisons d'écouteur sont semblables aux références de méthode, mais elles vous permettent d'exécuter des expressions de liaison de données arbitraires.
Question 2
Supposons que votre application inclut la ressource de chaîne suivante :<string name="generic_name">Hello %s</string>
Quelle syntaxe correspond à la mise en forme de la chaîne à l'aide de l'expression data-binding ?
android:text= "@{@string/generic_name(user.name)}"
android:text= "@{string/generic_name(user.name)}"
android:text= "@{@generic_name(user.name)}"
android:text= "@{@string/generic_name,user.name}"
Question 3
Quand une expression "binding-binding" est-elle évaluée et exécutée ?
- Lorsque les données soumises à une
LiveData
sont modifiées - Lorsqu'une activité est recréée par une modification de configuration
- Lorsqu'un événement tel que
onClick()
se produit - Lorsque l'activité passe en arrière-plan
Démarrez la leçon suivante :
Pour obtenir des liens vers d'autres ateliers de programmation dans ce cours, consultez la page de destination des ateliers de programmation Android Kotlin Fundamentals.