1. Avant de commencer
Dans les précédents ateliers de programmation, vous avez appris à utiliser un élément ViewModel
pour stocker les données de l'application. ViewModel
permet aux données de l'application de "survivre" aux changements de configuration. Dans cet atelier de programmation, vous allez apprendre à intégrer LiveData
aux données de ViewModel
.
LiveData
est une classe de conteneur de données qui fait également partie des composants d'architecture Android et qui peut être observée.
Conditions préalables
- Vous savez comment télécharger le code source depuis GitHub et l'ouvrir dans Android Studio.
- Vous savez comment créer et exécuter une application Android de base en langage Kotlin, à l'aide d'activités et de fragments.
- Vous comprenez le fonctionnement des cycles de vie des activités et des fragments.
- Vous savez comment conserver les données de l'UI en modifiant la configuration de l'appareil à l'aide de
ViewModel
. - Vous savez comment écrire des expressions lambda.
Points abordés
- Comment utiliser
LiveData
etMutableLiveData
dans votre application. - Comment encapsuler les données stockées dans un
ViewModel
avecLiveData
. - Comment ajouter des méthodes d'observation pour voir les modifications effectuées dans
LiveData.
. - Comment écrire des expressions de liaison dans un fichier de mise en page.
Objectifs de l'atelier
- Utiliser
LiveData
pour les données de l'application (mot, nombre de mots et score) dans l'application Unscramble. - Ajouter des méthodes d'observation qui reçoivent une notification lorsque les données changent, et mettre à jour automatiquement l'affichage de texte du mot brouillé.
- Écrire, dans le fichier de mise en page, des expressions de liaison qui sont déclenchées lorsque la classe
LiveData
sous-jacente est modifiée. Le score, le nombre de mots et les affichages de texte des mots brouillés sont mis à jour automatiquement.
Ce dont vous avez besoin
- Un ordinateur sur lequel est installé Android Studio.
- Code de solution de l'atelier de programmation précédent (application Unscramble avec
ViewModel
).
Télécharger le code de démarrage pour cet atelier de programmation
Cet atelier de programmation utilise l'application Unscramble que vous avez créée dans l'atelier précédent (Stocker des données dans ViewModel) comme code de démarrage.
2. Présentation de l'application de démarrage
Cet atelier de programmation utilise le code de solution Unscramble que vous avez découvert lors de l'atelier précédent. L'application affiche un mot brouillé que le joueur doit déchiffrer. Le nombre de tentatives est illimité. Les données de l'application, telles que le mot actuel, le score du joueur et le nombre de mots, sont enregistrées dans ViewModel
. Toutefois, l'UI de l'application n'affiche pas les nouvelles valeurs de score et de nombre de mots. Dans cet atelier de programmation, vous allez implémenter les fonctionnalités manquantes à l'aide de LiveData
.
3. Qu'est-ce que LiveData ?
LiveData
est une classe de conteneur de données observable, sensible au cycle de vie.
Voici quelques caractéristiques de LiveData
:
LiveData
contient des données ;LiveData
est un wrapper qui peut être utilisé avec n'importe quel type de données.LiveData
est une classe observable, ce qui signifie qu'un observateur est averti en cas de modification des données détenues par l'objetLiveData
.LiveData
est sensible au cycle de vie. Lorsque vous associez un observateur àLiveData
, il est associé à unLifecycleOwner
(il s'agit généralement d'une activité ou d'un fragment).LiveData
ne met à jour que les observateurs dont l'état de cycle de vie est actif, tels queSTARTED
ouRESUMED
. Pour en savoir plus surLiveData
et sur l'observation, cliquez ici.
Mise à jour de l'UI dans le code de démarrage
Dans le code de démarrage, la méthode updateNextWordOnScreen()
est appelée explicitement chaque fois que vous souhaitez afficher un nouveau mot brouillé dans l'UI. Cette méthode est appelée pendant l'initialisation du jeu et lorsque le joueur appuie sur le bouton Submit (Envoyer) ou Skip (Ignorer). L'appel est effectué à partir des méthodes onViewCreated()
, restartGame()
, onSkipWord()
et onSubmitWord()
. Avec Livedata
, il n'est pas nécessaire d'appeler cette méthode depuis plusieurs emplacements pour mettre à jour l'UI. Vous n'effectuez cette opération qu'une seule fois dans l'observateur.
4. Ajouter LiveData au mot brouillé actuel
Dans cette tâche, vous allez apprendre à encapsuler des données avec LiveData,
en convertissant le mot actuel dans GameViewModel
en LiveData
. Dans une tâche ultérieure, vous ajouterez un observateur à ces objets LiveData
et vous apprendrez à observer LiveData
.
MutableLiveData
MutableLiveData
est la version modifiable de la classe LiveData
. En d'autres termes, la valeur des données qu'elle contient peut être modifiée.
- Dans
GameViewModel
, remplacez le type de la variable_currentScrambledWord
parMutableLiveData
<String>
.LiveData
etMutableLiveData
sont des classes génériques. Vous devez donc spécifier le type de données qu'elles contiennent. - Définissez le type de variable
_currentScrambledWord
surval
, car la valeur de l'objetLiveData
/MutableLiveData
restera la même, et seules les données stockées dans l'objet seront modifiées.
private val _currentScrambledWord = MutableLiveData<String>()
- Remplacez le type
currentScrambledWord
du champ de stockage parLiveData<String>
, car il est immuable. Android Studio affiche des erreurs que vous corrigerez lors des prochaines étapes.
val currentScrambledWord: LiveData<String>
get() = _currentScrambledWord
- Pour accéder aux données d'un objet
LiveData
, utilisez la propriétévalue
. DansGameViewModel
, dans le blocelse
de la méthodegetNextWord()
, remplacez la référence de_currentScrambledWord
par_currentScrambledWord.value
.
private fun getNextWord() {
...
} else {
_currentScrambledWord.value = String(tempWord)
...
}
}
5. Associer un observateur à l'objet LiveData
Dans cette tâche, vous allez configurer un observateur dans le composant d'application GameFragment
. L'observateur que vous allez ajouter observe les modifications apportées aux données de l'application currentScrambledWord
. 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. Ainsi, l'observateur situé dans GameFragment
n'est averti que lorsque l'état de GameFragment
est STARTED
ou RESUMED
.
- Dans
GameFragment
, supprimez la méthodeupdateNextWordOnScreen()
et tous les appels associés. Vous n'avez pas besoin de cette méthode, car vous allez associer un observateur àLiveData
. - Dans
onSubmitWord()
, modifiez le blocif-else
vide comme suit. La méthode complète doit ressembler à ceci :
private fun onSubmitWord() {
val playerWord = binding.textInputEditText.text.toString()
if (viewModel.isUserWordCorrect(playerWord)) {
setErrorTextField(false)
if (!viewModel.nextWord()) {
showFinalScoreDialog()
}
} else {
setErrorTextField(true)
}
}
- Associez un observateur pour
currentScrambledWord
LiveData
. DansGameFragment
, à la fin du rappelonViewCreated()
, appelez la méthodeobserve()
surcurrentScrambledWord
.
// Observe the currentScrambledWord LiveData.
viewModel.currentScrambledWord.observe()
Android Studio affiche une erreur pour indiquer qu'il manque des paramètres. Vous corrigerez cette erreur à l'étape suivante.
- Transmettez
viewLifecycleOwner
en tant que premier paramètre à la méthodeobserve()
.viewLifecycleOwner
représente le cycle de vie de la vue de Fragment. Ce paramètre aideLiveData
à prendre en compte le cycle de vieGameFragment
et à n'avertir l'observateur que lorsqueGameFragment
est dans un état actif (STARTED
ouRESUMED
). - Ajoutez un lambda en tant que deuxième paramètre avec
newWord
comme paramètre de fonction.newWord
contiendra la nouvelle valeur du mot brouillé.
// Observe the scrambledCharArray LiveData, passing in the LifecycleOwner and the observer.
viewModel.currentScrambledWord.observe(viewLifecycleOwner,
{ newWord ->
})
Une expression lambda est une fonction anonyme non déclarée, mais transmise immédiatement en tant qu'expression. Une expression lambda est toujours placée entre accolades { }.
- Dans le corps de fonction de l'expression lambda, affectez
newWord
à l'affichage de texte du mot brouillé.
// Observe the scrambledCharArray LiveData, passing in the LifecycleOwner and the observer.
viewModel.currentScrambledWord.observe(viewLifecycleOwner,
{ newWord ->
binding.textViewUnscrambledWord.text = newWord
})
- Compilez et exécutez l'application. Votre jeu devrait fonctionner exactement comme auparavant, si ce n'est que l'affichage du mot brouillé est maintenant mis à jour automatiquement dans l'observateur
LiveData
, et non dans la méthodeupdateNextWordOnScreen()
.
6. Associer l'observateur au score et au nombre de mots
Comme dans la tâche précédente, vous allez ajouter LiveData
aux autres données de l'application (le score et le nombre de mots) afin que l'UI soit mise à jour avec les valeurs correctes du score et du nombre de mots en cours de partie.
Étape 1 : Encapsulez le score et le nombre de mots avec LiveData
- Dans
GameViewModel
, remplacez le type des variables de classe_score
et_currentWordCount
parval
. - Remplacez le type de données des variables
_score
et_currentWordCount
parMutableLiveData
, puis initialisez-les sur0
. - Définissez le type des champs de stockage sur
LiveData<Int>
.
private val _score = MutableLiveData(0)
val score: LiveData<Int>
get() = _score
private val _currentWordCount = MutableLiveData(0)
val currentWordCount: LiveData<Int>
get() = _currentWordCount
- Dans
GameViewModel
, au début de la méthodereinitializeData()
, remplacez la référence de_score
et_currentWordCount
par_score.
value
et_currentWordCount.
value
, respectivement.
fun reinitializeData() {
_score.value = 0
_currentWordCount.value = 0
wordsList.clear()
getNextWord()
}
- Dans
GameViewModel
, à l'intérieur de la méthodenextWord()
, remplacez la référence de_currentWordCount
par_currentWordCount.
value!!
.
fun nextWord(): Boolean {
return if (_currentWordCount.value!! < MAX_NO_OF_WORDS) {
getNextWord()
true
} else false
}
- Dans
GameViewModel
, à l'intérieur des méthodesincreaseScore()
etgetNextWord()
, remplacez la référence de_score
et_currentWordCount
par_score.
value
et_currentWordCount.
value
, respectivement. Android Studio affiche une erreur, car_score
n'est plus un entier, maisLiveData
. Vous allez résoudre ce problème lors des prochaines étapes. - Utilisez la fonction Kotlin
plus()
pour augmenter la valeur_score
. Cette fonction effectue l'ajout avec une sécurité nulle (null-safety).
private fun increaseScore() {
_score.value = (_score.value)?.plus(SCORE_INCREASE)
}
- De même, utilisez la fonction Kotlin
inc()
pour augmenter la valeur d'une unité avec une sécurité nulle.
private fun getNextWord() {
...
} else {
_currentScrambledWord.value = String(tempWord)
_currentWordCount.value = (_currentWordCount.value)?.inc()
wordsList.add(currentWord)
}
}
- Dans
GameFragment
, accédez à la valeur descore
à l'aide de la propriétévalue
. Dans la méthodeshowFinalScoreDialog()
, remplacezviewModel.score
parviewModel.score.
value
.
private fun showFinalScoreDialog() {
MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.congratulations))
.setMessage(getString(R.string.you_scored, viewModel.score.value))
...
.show()
}
Étape 2 : Associez des observateurs au score et au nombre de mots
Dans l'application, le score et le nombre de mots ne sont pas mis à jour. Vous allez les mettre à jour dans cette tâche à l'aide d'observateurs LiveData
.
- Dans
GameFragment
, à l'intérieur de la méthodeonViewCreated()
, supprimez le code qui met à jour les affichages de texte du score et du nombre de mots.
Supprimez :
binding.score.text = getString(R.string.score, 0)
binding.wordCount.text = getString(R.string.word_count, 0, MAX_NO_OF_WORDS)
- Dans
GameFragment
, à la fin de la méthodeonViewCreated()
, associez un observateur pourscore
. TransmettezviewLifecycleOwner
en tant que premier paramètre à l'observateur et une expression lambda pour le deuxième paramètre. Dans l'expression lambda, transmettez le nouveau score en tant que paramètre et, dans le corps de la fonction, définissez le nouveau score sur l'affichage de texte.
viewModel.score.observe(viewLifecycleOwner,
{ newScore ->
binding.score.text = getString(R.string.score, newScore)
})
- À la fin de la méthode
onViewCreated()
, associez un observateur pourcurrentWordCount
LiveData
. TransmettezviewLifecycleOwner
en tant que premier paramètre à l'observateur et une expression lambda pour le deuxième paramètre. Dans l'expression lambda, transmettez le nouveau nombre de mots en tant que paramètre et, dans le corps de la fonction, définissez le nouveau nombre de mots avecMAX_NO_OF_WORDS
sur l'affichage de texte.
viewModel.currentWordCount.observe(viewLifecycleOwner,
{ newWordCount ->
binding.wordCount.text =
getString(R.string.word_count, newWordCount, MAX_NO_OF_WORDS)
})
Les nouveaux observateurs seront déclenchés lors de la modification de la valeur du score et du nombre de mots dans ViewModel
, et ce, pendant toute la durée de vie du propriétaire du cycle de vie, à savoir GameFragment
.
- Exécutez l'application pour voir la magie s'opérer. Essayez de deviner quelques mots. Le score et le nombre de mots sont également mis à jour correctement à l'écran. Notez que vous ne mettez pas à jour ces affichages de texte en fonction de certaines conditions du code.
score
etcurrentWordCount
correspondent àLiveData
, et les observateurs correspondants sont automatiquement appelés lorsque la valeur sous-jacente change.
7. Utiliser LiveData avec une liaison de données
Dans les tâches précédentes, votre application écoutait les modifications de données dans le code. De la même manière, les applications peuvent écouter les modifications de données en provenance de la mise en page. Avec la liaison de données, lorsqu'une valeur LiveData
observable est modifiée, les éléments d'UI de la mise en page auxquels elle est liée en sont également informés, et l'UI peut être mise à jour à partir de la mise en page.
Concept : liaison de données
Dans les ateliers de programmation précédents, vous avez découvert View Binding (Liaison de vue), qui est une liaison unidirectionnelle. Vous pouvez lier des affichages au code, mais pas l'inverse.
Rappel pour la liaison de vue :
La liaison de vue est une fonctionnalité qui vous permet d'accéder plus facilement aux affichages dans le code. Elle génère une classe de liaison pour chaque fichier de mise en page XML. Une instance d'une classe de liaison contient des références directes à tous les affichages qui possèdent un ID dans la mise en page correspondante. Par exemple, l'application Unscramble utilise actuellement la fonctionnalité de liaison de vue, de sorte que les affichages puissent être référencés dans le code à l'aide de la classe de liaison générée.
Exemple :
binding.textViewUnscrambledWord.text = newWord
binding.score.text = getString(R.string.score, newScore)
binding.wordCount.text =
getString(R.string.word_count, newWordCount, MAX_NO_OF_WORDS)
La fonctionnalité de liaison de vue ne vous permet pas de référencer les données de l'application dans les affichages (fichiers de mise en page). Pour ce faire, utilisez la liaison de données.
Liaison de données
La bibliothèque Data Binding fait également partie de la bibliothèque Android Jetpack. La liaison de données lie les composants de l'UI de vos mises en page aux sources de données de votre application à l'aide d'un format déclaratif, que nous étudierons dans la suite de cet atelier.
Pour faire simple, la liaison de données consiste à lier les données (à partir du code) aux vues et à lier les vues (liaison de vues au code) :
Exemple d'utilisation de la liaison de vue dans le contrôleur d'UI
binding.textViewUnscrambledWord.text = viewModel.currentScrambledWord
Exemple d'utilisation de la liaison de données dans un fichier de mise en page
android:text="@{gameViewModel.currentScrambledWord}"
L'exemple ci-dessus montre comment utiliser la bibliothèque Data Binding pour affecter directement des données d'application aux affichages/widgets dans le fichier de mise en page. Notez l'utilisation de la syntaxe @{}
dans l'expression d'affectation.
Le principal avantage de la liaison de données est de vous permettre de supprimer de nombreux appels de framework d'UI dans vos activités, ce qui les rend plus simples et plus faciles à gérer. Cela peut également améliorer les performances de votre application, et empêcher les fuites de mémoire et les exceptions de pointeur nul.
Étape 1 : Remplacez la liaison de vue par la liaison de données
- Dans le fichier
build.gradle(Module)
, activez la propriétédataBinding
dans la sectionbuildFeatures
.
Remplacez
buildFeatures {
viewBinding = true
}
par
buildFeatures {
dataBinding = true
}
Effectuez une synchronisation Gradle lorsque vous y êtes invité par Android Studio.
- Pour utiliser la liaison de données dans n'importe quel projet Kotlin, vous devez appliquer le plug-in
kotlin-kapt
. Cette étape a déjà été effectuée dans le fichierbuild.gradle(Module)
.
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
Les étapes ci-dessus génèrent automatiquement une classe de liaison pour chaque fichier XML de mise en page dans l'application. Si le nom du fichier de mise en page est activity_main.xml
, votre classe de génération automatique s'appelle ActivityMainBinding
.
Étape 2 : Convertissez le fichier de mise en page en mise en page de liaison de données
Les fichiers de mise en page de la liaison de données sont légèrement différents et commencent par la balise racine <layout>
, suivie d'un élément <data>
facultatif et d'un élément racine view
. Cet élément de vue correspond à ce que serait votre élément racine dans un fichier de mise en page sans liaison.
- Ouvrez
game_fragment.xml
, puis sélectionnez l'onglet Code. - Pour convertir la mise en page en une mise en page de liaison de données, encapsulez l'élément racine dans une balise
<layout>
. Vous devez également déplacer les définitions de l'espace de noms (attributs commençant parxmlns:
) vers le nouvel élément racine. Ajoutez des balises<data></data>
à l'intérieur de la balise<layout>
située au-dessus de l'élément racine. Android Studio propose une méthode pratique pour effectuer cette opération automatiquement : effectuez un clic droit sur l'élément racine (ScrollView
), sélectionnez Show Context Actions > Convert to data binding layout (Afficher les actions contextuelles > Convertir en mise en page de liaison de données).
- Votre mise en page doit se présenter comme suit :
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
...
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</layout>
- Dans
GameFragment
, au début de la méthodeonCreateView()
, modifiez l'instanciation de la variablebinding
pour qu'elle utilise la liaison de données.
Remplacez
binding = GameFragmentBinding.inflate(inflater, container, false)
par
binding = DataBindingUtil.inflate(inflater, R.layout.game_fragment, container, false)
- Compilez le code. Cela devrait se faire sans aucun problème. Votre application utilise à présent la liaison de données, et les vues de la mise en page peuvent accéder aux données de l'application.
8. Ajouter des variables de liaison de données
Dans cette tâche, vous allez ajouter des propriétés dans le fichier de mise en page afin d'accéder aux données de l'application à partir de viewModel
. Vous allez initialiser les variables de mise en page dans le code.
- Dans
game_fragment.xml
, à l'intérieur de la balise<data>
, ajoutez une balise enfant nommée<variable>
et déclarez une propriétégameViewModel
de typeGameViewModel
. Vous l'utiliserez pour lier les données deViewModel
à la mise en page.
<data>
<variable
name="gameViewModel"
type="com.example.android.unscramble.ui.game.GameViewModel" />
</data>
Notez que le type gameViewModel
contient le nom du package. Assurez-vous que ce nom de package correspond à celui indiqué dans votre application.
- Sous la déclaration
gameViewModel
, ajoutez une autre variable de typeInteger
dans la balise<data>
et nommez-lamaxNoOfWords
. Vous l'utiliserez pour créer une liaison avec la variable dans ViewModel afin de stocker le nombre de mots par jeu.
<data>
...
<variable
name="maxNoOfWords"
type="int" />
</data>
- Dans
GameFragment
, au début de la méthodeonViewCreated()
, initialisez les variables de mise en pagegameViewModel
etmaxNoOfWords
.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.gameViewModel = viewModel
binding.maxNoOfWords = MAX_NO_OF_WORDS
...
}
LiveData
est une classe observable et sensible au cycle de vie. Vous devez donc transmettre le propriétaire du cycle de vie à la mise en page. DansGameFragment
, ajoutez le code suivant dans la méthodeonViewCreated()
, sous l'initialisation des variables de liaison.
// Specify the fragment view as the lifecycle owner of the binding.
// This is used so that the binding can observe LiveData updates
binding.lifecycleOwner = viewLifecycleOwner
Pour rappel, vous avez mis en œuvre une fonctionnalité similaire lorsque vous avez implémenté les observateurs LiveData
. Vous avez transmis viewLifecycleOwner
en tant que paramètre aux observateurs LiveData
.
9. Utiliser des expressions de liaison
Les expressions de liaison sont écrites dans la mise en page, dans les propriétés d'attribut (comme android:text
) faisant référence aux propriétés de mise en page. Les propriétés de mise en page sont déclarées en haut du fichier de mise en page de la liaison de données, au moyen de la balise <variable>
. Lorsque l'une des variables dépendantes change, la bibliothèque Data Binding exécute vos expressions de liaison (et met donc à jour les affichages). Cette détection des modifications constitue une excellente optimisation (que vous pouvez obtenir sans frais) lors de l'utilisation d'une bibliothèque Data Binding.
Syntaxe des expressions de liaison
Les expressions de liaison commencent par un symbole @
et sont encapsulées dans des accolades {}
. Dans l'exemple suivant, le texte TextView
est défini sur la propriété firstName
de la variable user
:
Exemple :
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}" />
Étape 1 : Ajoutez une expression de liaison au mot actuel
Au cours de cette étape, vous allez lier l'affichage du mot actuel à l'objet LiveData
dans ViewModel
.
- Dans
game_fragment.xml
, ajoutez un attributtext
à l'affichage de textetextView_unscrambled_word
. Utilisez la nouvelle variable de mise en pagegameViewModel
et affectez@{gameViewModel.currentScrambledWord}
à l'attributtext
.
<TextView
android:id="@+id/textView_unscrambled_word"
...
android:text="@{gameViewModel.currentScrambledWord}"
.../>
- Dans
GameFragment
, supprimez le code d'observateurLiveData
pourcurrentScrambledWord
: vous n'avez plus besoin de ce code dans le fragment. La mise en page reçoit directement les mises à jour des modifications apportées àLiveData
.
Supprimez :
viewModel.currentScrambledWord.observe(viewLifecycleOwner,
{ newWord ->
binding.textViewUnscrambledWord.text = newWord
})
- Exécutez votre application. Elle devrait fonctionner comme auparavant. À présent, l'affichage de texte du mot brouillé utilise les expressions de liaison pour mettre à jour l'UI, et non les observateurs
LiveData
.
Étape 2 : Ajoutez une expression de liaison au score et au nombre de mots
Ressources dans les expressions de liaison de données
Une expression de liaison de données peut référencer des ressources d'application avec la syntaxe suivante.
Exemple :
android:padding="@{@dimen/largePadding}"
Dans l'exemple ci-dessus, la valeur largePadding
provenant du fichier de ressources dimen.xml
est affectée à l'attribut padding
.
Vous pouvez également transmettre des propriétés de mise en page en tant que paramètres de ressource.
Exemple :
android:text="@{@string/example_resource(user.lastName)}"
strings.xml
<string name="example_resource">Last Name: %s</string>
Dans l'exemple ci-dessus, example_resource
est une ressource de chaîne avec l'espace réservé %s
. Vous transmettez user.lastName
en tant que paramètre de ressource dans l'expression de liaison, où user
est une variable de mise en page.
Au cours de cette étape, vous allez ajouter des expressions de liaison aux affichages de texte du score et du nombre de mots, en transmettant les paramètres de ressource. Cette étape est semblable à celle que vous avez suivie pour textView_unscrambled_word
ci-dessus.
- Dans
game_fragment.xml
, mettez à jour l'attributtext
pour l'affichage de texteword_count
avec l'expression de liaison suivante. Utilisez la ressource de chaîneword_count
, et transmettezgameViewModel.currentWordCount
etmaxNoOfWords
comme paramètres de ressource.
<TextView
android:id="@+id/word_count"
...
android:text="@{@string/word_count(gameViewModel.currentWordCount, maxNoOfWords)}"
.../>
- Mettez à jour l'attribut
text
pour l'affichage de textescore
avec l'expression de liaison suivante. Utilisez la ressource de chaînescore
et transmettezgameViewModel.score
comme paramètre de ressource.
<TextView
android:id="@+id/score"
...
android:text="@{@string/score(gameViewModel.score)}"
... />
- Supprimez les observateurs
LiveData
deGameFragment
. Vous n'en avez plus besoin. Les expressions de liaison mettent à jour l'UI lorsque la classeLiveData
correspondante change.
Supprimez :
viewModel.score.observe(viewLifecycleOwner,
{ newScore ->
binding.score.text = getString(R.string.score, newScore)
})
viewModel.currentWordCount.observe(viewLifecycleOwner,
{ newWordCount ->
binding.wordCount.text =
getString(R.string.word_count, newWordCount, MAX_NO_OF_WORDS)
})
- Exécutez l'application et essayez de deviner quelques mots. Votre code utilise à présent
LiveData
et des expressions de liaison pour mettre à jour l'UI.
Félicitations ! Vous savez maintenant comment utiliser LiveData
avec des observateurs LiveData
et LiveData
avec des expressions de liaison.
10. Tester l'application Unscramble avec TalkBack activé
L'objectif, tout au long de ce cours, est de créer des applications accessibles au plus grand nombre d'utilisateurs possible. Certains utilisateurs peuvent utiliser Talkback pour accéder à votre appli et la parcourir. TalkBack est le lecteur d'écran de Google intégré aux appareils Android. Cette fonctionnalité est destinée à fournir des commentaires audio pour vous aider dans l'utilisation de votre appareil sans regarder l'écran.
Assurez-vous qu'il est possible de jouer à ce jeu lorsque TalkBack est activé.
- Activez TalkBack sur votre appareil en suivant ces instructions.
- Revenez à l'application Unscramble.
- Explorez votre application avec TalkBack en suivant ces instructions. Balayez l'écran vers la droite pour parcourir les éléments de l'écran dans l'ordre, puis vers la gauche pour procéder dans la direction opposée. Appuyez deux fois n'importe où pour effectuer une sélection. Vérifiez que vous pouvez accéder à tous les éléments de votre application à l'aide des gestes de balayage.
- Assurez-vous qu'un utilisateur de TalkBack peut accéder à chaque élément affiché à l'écran.
- Comme vous pouvez le constater, TalkBack essaie de lire le mot brouillé comme s'il s'agissait d'un mot. Cela peut prêter à confusion pour le joueur, car ce n'est pas un mot du dictionnaire.
- L'idéal serait que TalkBack lise à voix haute chaque caractère qui compose le mot brouillé. Dans l'élément
GameViewModel
, convertissez le mot brouilléString
en une chaîneSpannable
. Une chaîne Spannable est une chaîne à laquelle sont associées des informations supplémentaires. Dans le cas présent, nous voulons associer la chaîne à un élémentTtsSpan
TYPE_VERBATIM
afin que le moteur de synthèse vocale lise à voix haute le mot brouillé, caractère par caractère. - Dans
GameViewModel
, utilisez le code suivant pour modifier la méthode de déclaration de la variablecurrentScrambledWord
:
val currentScrambledWord: LiveData<Spannable> = Transformations.map(_currentScrambledWord) {
if (it == null) {
SpannableString("")
} else {
val scrambledWord = it.toString()
val spannable: Spannable = SpannableString(scrambledWord)
spannable.setSpan(
TtsSpan.VerbatimBuilder(scrambledWord).build(),
0,
scrambledWord.length,
Spannable.SPAN_INCLUSIVE_INCLUSIVE
)
spannable
}
}
Cette variable est maintenant LiveData<Spannable>
au lieu de LiveData<String>
. Vous n'avez pas à comprendre tous les mécanismes de fonctionnement. Sachez simplement que l'implémentation utilise une transformation LiveData
pour convertir le mot brouillé actuel String
en une chaîne Spannable pouvant être gérée correctement par le service d'accessibilité. Dans l'atelier de programmation suivant, vous en apprendrez davantage sur les transformations LiveData
. Celles-ci vous permettent de renvoyer une instance LiveData
différente en fonction de la valeur de la classe LiveData
correspondante.
- Exécutez l'application Unscramble, puis explorez-la avec TalkBack. TalkBack devrait maintenant lire à voix haute chaque caractère du mot brouillé.
Consultez ces principes pour savoir comment améliorer l'accessibilité de votre application.
11. Supprimer le code inutilisé
Il est recommandé de supprimer tout code inutile, non utilisé ou indésirable pour la solution. Non seulement cela facilite la gestion du code, mais cela permet aussi aux nouveaux collaborateurs de mieux le comprendre.
- Dans
GameFragment
, supprimez les méthodesgetNextScrambledWord()
etonDetach()
. - Dans
GameViewModel
, supprimez la méthodeonCleared()
. - Supprimez toutes les importations inutilisées en haut des fichiers sources. Elles apparaissent en grisé.
Vous n'avez plus besoin des instructions de journalisation. Vous pouvez donc les supprimer du code si vous le souhaitez.
- [Facultatif] Dans les fichiers sources (
GameFragment.kt
etGameViewModel.kt
), supprimez les instructionsLog
que vous avez ajoutées dans l'atelier de programmation précédent afin de comprendre le cycle de vie deViewModel
.
12. Code de solution
Le code de solution de cet atelier de programmation figure dans le projet ci-dessous.
- Accédez à la page du dépôt GitHub fournie pour le projet.
- Vérifiez que le nom de la branche correspond à celui spécifié dans l'atelier de programmation. Par exemple, dans la capture d'écran suivante, le nom de la branche est main.
- Sur la page GitHub du projet, cliquez sur le bouton Code pour afficher une fenêtre pop-up.
- Dans la fenêtre pop-up, cliquez sur le bouton Download ZIP (Télécharger le fichier ZIP) pour enregistrer le projet sur votre ordinateur. Attendez la fin du téléchargement.
- Recherchez le fichier sur votre ordinateur (il se trouve probablement dans le dossier Téléchargements).
- Double-cliquez sur le fichier ZIP pour le décompresser. Un dossier contenant les fichiers du projet est alors créé.
Ouvrir le projet dans Android Studio
- Lancez Android Studio.
- Dans la fenêtre Welcome to Android Studio (Bienvenue dans Android Studio), cliquez sur Open (Ouvrir).
Remarque : Si Android Studio est déjà ouvert, sélectionnez l'option de menu File > Open (Fichier > Ouvrir).
- Dans l'explorateur de fichiers, accédez à l'emplacement du dossier du projet décompressé (il se trouve probablement dans le dossier Téléchargements).
- Double-cliquez sur le dossier de ce projet.
- Attendez qu'Android Studio ouvre le projet.
- Cliquez sur le bouton Run (Exécuter) pour créer et exécuter l'application. Assurez-vous qu'elle fonctionne correctement.
13. Résumé
LiveData
contient des données ;LiveData
est un wrapper qui peut être utilisé avec n'importe quelle donnée.LiveData
est une classe observable, ce qui signifie qu'un observateur est averti en cas de modification des données détenues par l'objetLiveData
.LiveData
est sensible au cycle de vie. Lorsque vous associez un observateur àLiveData
, il est associé à unLifecycleOwner
(il s'agit généralement d'une activité ou d'un fragment). La classe LiveData ne met à jour que les observateurs dont l'état de cycle de vie est actif, tels queSTARTED
ouRESUMED
. Pour en savoir plus surLiveData
et sur l'observation, cliquez ici.- Les applications peuvent écouter les modifications de la classe LiveData en provenance de la mise en page à l'aide de la liaison de données et d'expressions de liaison.
- Les expressions de liaison sont écrites dans la mise en page, dans les propriétés d'attribut (comme
android:text
) faisant référence aux propriétés de mise en page.
14. En savoir plus
- Présentation de LiveData
- Documentation de référence de l'API Observateur LiveData
- Liaison de données
- Liaison de données bidirectionnelle
Articles de blog