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 les ateliers de programmation précédents de ce cours, vous avez utilisé la fonction findViewById()
pour obtenir des références aux vues. Lorsque votre application comporte des hiérarchies de vues complexes, findViewById()
est coûteux et ralentit l'application, car Android parcourt la hiérarchie de vues, en commençant par la racine, jusqu'à ce qu'il trouve la vue souhaitée. Heureusement, il existe une meilleure solution.
Pour définir des données dans les vues, vous avez utilisé des ressources de chaîne et défini les données à partir de l'activité. Il serait plus efficace que la vue connaisse les données. Et heureusement, c'est possible.
Dans cet atelier de programmation, vous allez apprendre à utiliser la liaison de données pour éliminer le besoin de findViewById()
. Vous apprendrez également à utiliser la liaison de données pour accéder aux données directement à partir d'une vue.
Ce que vous devez déjà savoir
Vous devez maîtriser les éléments suivants :
- Qu'est-ce qu'une activité et comment en configurer une avec une mise en page dans
onCreate()
? - Créer une vue de texte et définir le texte qu'elle affiche.
- Utiliser
findViewById()
pour obtenir une référence à une vue. - Créer et modifier une mise en page XML de base pour une vue.
Points abordés
- Comment utiliser la bibliothèque Data Binding pour éliminer les appels inefficaces vers
findViewById()
. - Accéder aux données de l'application directement à partir du fichier XML.
Objectifs de l'atelier
- Modifier une application pour qu'elle utilise le data binding au lieu de
findViewById()
et pour qu'elle accède aux données directement à partir des fichiers XML de mise en page.
Dans cet atelier de programmation, vous allez commencer par l'application AboutMe et la modifier pour qu'elle utilise la liaison de données. L'application sera exactement la même une fois que vous aurez terminé.
Voici ce que fait l'application AboutMe :
- Lorsque l'utilisateur ouvre l'application, celle-ci affiche un nom, un champ permettant de saisir un pseudonyme, un bouton OK, une image d'étoile et du texte défilant.
- L'utilisateur peut saisir un pseudo et appuyer sur le bouton OK. Le champ modifiable et le bouton sont remplacés par une vue de texte qui affiche le pseudo saisi.
Vous pouvez utiliser le code que vous avez créé dans l'atelier de programmation précédent ou télécharger le code AboutMeDataBinding-Starter depuis GitHub.
Le code que vous avez écrit dans les ateliers de programmation précédents utilise la fonction findViewById()
pour obtenir des références aux vues.
Chaque fois que vous utilisez findViewById()
pour rechercher une vue après sa création ou sa recréation, le système Android parcourt la hiérarchie des vues au moment de l'exécution pour la trouver. Lorsque votre application ne comporte que quelques vues, cela ne pose pas de problème. Toutefois, les applications de production peuvent comporter des dizaines de vues dans une mise en page, et même avec la meilleure conception, il y aura des vues imbriquées.
Imaginez une mise en page linéaire contenant une vue de défilement qui contient une vue de texte. Pour une hiérarchie de vues volumineuse ou profonde, la recherche d'une vue peut prendre suffisamment de temps pour ralentir sensiblement l'application pour l'utilisateur. La mise en cache des vues dans des variables peut être utile, mais vous devez toujours initialiser une variable pour chaque vue, dans chaque espace de noms. Avec de nombreuses vues et activités, cela s'accumule également.
Une solution consiste à créer un objet contenant une référence à chaque vue. Cet objet, appelé objet Binding
, peut être utilisé par l'ensemble de votre application. Cette technique est appelée liaison de données. Une fois qu'un objet de liaison a été créé pour votre application, vous pouvez accéder aux vues et à d'autres données via l'objet de liaison, sans avoir à parcourir la hiérarchie des vues ni à rechercher les données.
L'association de données présente les avantages suivants :
- Le code est plus court, plus facile à lire et plus facile à gérer que le code qui utilise
findByView()
. - Les données et les vues sont clairement séparées. Cet avantage de la liaison de données deviendra de plus en plus important au cours de ce cours.
- Le système Android ne parcourt la hiérarchie des vues qu'une seule fois pour obtenir chaque vue. Cela se produit au démarrage de l'application, et non au moment de l'exécution lorsque l'utilisateur interagit avec l'application.
- Vous bénéficiez de la sécurité du typage pour accéder aux vues. (La sûreté de typage signifie que le compilateur valide les types lors de la compilation et génère une erreur si vous essayez d'attribuer le mauvais type à une variable.)
Dans cette tâche, vous allez configurer la liaison de données et l'utiliser pour remplacer les appels à findViewById()
par des appels à l'objet de liaison.
Étape 1 : Activez la liaison de données
Pour utiliser la liaison de données, vous devez l'activer dans votre fichier Gradle, car elle n'est pas activée par défaut. En effet, la liaison de données augmente le temps de compilation et peut affecter le temps de démarrage de l'application.
- Si vous n'avez pas l'application AboutMe d'un atelier de programmation précédent, récupérez le code AboutMeDataBinding-Starter sur GitHub. Ouvrez-le dans Android Studio.
- Ouvrez le fichier
build.gradle (Module: app)
. - Dans la section
android
, avant l'accolade fermante, ajoutez une sectiondataBinding
et définissezenabled
surtrue
.
dataBinding {
enabled = true
}
- Lorsque vous y êtes invité, synchronisez le projet. Si vous n'y êtes pas invité, sélectionnez File > Sync Project with Gradle Files (Fichier > Synchroniser le projet avec les fichiers Gradle).
- Vous pouvez exécuter l'application, mais vous ne verrez aucune modification.
Étape 2 : Modifiez le fichier de mise en page pour qu'il puisse être utilisé avec la liaison de données
Pour utiliser la liaison de données, vous devez encapsuler votre mise en page XML avec une balise <layout>
. La classe racine n'est donc plus un groupe de vues, mais une mise en page contenant des groupes de vues et des vues. L'objet de liaison peut alors connaître la mise en page et les vues qu'elle contient.
- Ouvrez le fichier
activity_main.xml
. - Accédez à l'onglet Texte.
- Ajoutez
<layout></layout>
en tant que balise extérieure autour de<LinearLayout>
.
<layout>
<LinearLayout ... >
...
</LinearLayout>
</layout>
- Sélectionnez Code > Remettre en forme le code pour corriger l'indentation du code.
Les déclarations d'espace de noms d'une mise en page doivent se trouver dans la balise la plus externe.
- Coupez les déclarations d'espace de noms de
<LinearLayout>
et collez-les dans la balise<layout>
. Votre balise d'ouverture<layout>
doit se présenter comme indiqué ci-dessous, et la balise<LinearLayout>
ne doit contenir que des propriétés d'affichage.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- Créez et exécutez votre application pour vérifier que vous avez effectué cette opération correctement.
Étape 3 : Créez un objet de liaison dans l'activité principale
Ajoutez une référence à l'objet de liaison à l'activité principale, afin de pouvoir l'utiliser pour accéder aux vues :
- Ouvrez le fichier
MainActivity.kt
. - Avant
onCreate()
, au niveau supérieur, créez une variable pour l'objet de liaison. Cette variable est généralement appeléebinding
.
Le type debinding
, la classeActivityMainBinding
, est créé par le compilateur spécifiquement pour cette activité principale. Le nom est dérivé du nom du fichier de mise en page, à savoiractivity_main + Binding
.
private lateinit var binding: ActivityMainBinding
- Importez
ActivityMainBinding
, si Android Studio vous le demande. Si vous n'y êtes pas invité, cliquez surActivityMainBinding
et appuyez surAlt+Enter
(Option+Enter
sur Mac) pour importer cette classe manquante. (Pour en savoir plus sur les raccourcis clavier, consultez Raccourcis clavier.)
L'instructionimport
doit ressembler à celle ci-dessous.
import com.example.android.aboutme.databinding.ActivityMainBinding
Ensuite, remplacez la fonction setContentView()
actuelle par une instruction qui effectue les opérations suivantes :
- Crée l'objet de liaison.
- Utilise la fonction
setContentView()
de la classeDataBindingUtil
pour associer la mise en pageactivity_main
àMainActivity
. Cette fonctionsetContentView()
s'occupe également de la configuration de la liaison de données pour les vues.
- Dans
onCreate()
, remplacez l'appelsetContentView()
par la ligne de code suivante.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Importez
DataBindingUtil
.
import androidx.databinding.DataBindingUtil
Étape 4 : Utilisez l'objet de liaison pour remplacer tous les appels à findViewById()
Vous pouvez maintenant remplacer tous les appels à findViewById()
par des références aux vues qui se trouvent dans l'objet de liaison. Lorsque l'objet de liaison est créé, le compilateur génère les noms des vues dans l'objet de liaison à partir des ID des vues dans la mise en page, en les convertissant en casse mixte. Par exemple, done_button
devient doneButton
dans l'objet de liaison, nickname_edit
devient nicknameEdit
et nickname_text
devient nicknameText
.
- Dans
onCreate()
, remplacez le code qui utilisefindViewById()
pour trouver ledone_button
par le code qui fait référence au bouton dans l'objet de liaison.
Remplacez ce code :findViewById<Button>(R.id.
done_button
)
par :binding.doneButton
Votre code final pour définir l'écouteur de clics dansonCreate()
devrait ressembler à ceci.
binding.doneButton.setOnClickListener {
addNickname(it)
}
- Faites de même pour tous les appels à
findViewById()
dans la fonctionaddNickname()
.
Remplacez toutes les occurrences defindViewById<
View
>(R.id.
id_view
)
parbinding.
idView
. Pour ce faire :
- Supprimez les définitions des variables
editText
etnicknameTextView
ainsi que leurs appels àfindViewById()
. Cela générera des erreurs. - Corrigez les erreurs en obtenant les vues
nicknameText
,nicknameEdit
etdoneButton
à partir de l'objetbinding
au lieu des variables (supprimées). - Remplacez
view.visibility
parbinding.doneButton.visibility
. L'utilisation debinding.doneButton
au lieu deview
transmis rend le code plus cohérent.
Le résultat est le code suivant :
binding.nicknameText.text = binding.nicknameEdit.text
binding.nicknameEdit.visibility = View.GONE
binding.doneButton.visibility = View.GONE
binding.nicknameText.visibility = View.VISIBLE
- Le fonctionnement reste inchangé. Vous pouvez éventuellement supprimer le paramètre
view
et mettre à jour toutes les utilisations deview
pour utiliserbinding.doneButton
dans cette fonction.
nicknameText
nécessite unString
, etnicknameEdit.text
est unEditable
. Lorsque vous utilisez la liaison de données, il est nécessaire de convertir explicitement leEditable
enString
.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
- Vous pouvez supprimer les importations grisées.
- Kotlinisez la fonction à l'aide de
apply{}
.
binding.apply {
nicknameText.text = nicknameEdit.text.toString()
nicknameEdit.visibility = View.GONE
doneButton.visibility = View.GONE
nicknameText.visibility = View.VISIBLE
}
- Compilez et exécutez votre application. Elle devrait avoir le même aspect et fonctionner exactement comme avant.
Vous pouvez tirer parti de la liaison de données pour rendre une classe de données directement disponible dans une vue. Cette technique simplifie le code et est extrêmement utile pour gérer les cas plus complexes.
Dans cet exemple, au lieu de définir le nom et le surnom à l'aide de ressources de chaîne, vous allez créer une classe de données pour le nom et le surnom. Vous mettez la classe de données à la disposition de la vue à l'aide de la liaison de données.
Étape 1 : Créer la classe de données MyName
- Dans Android Studio, dans le répertoire
java
, ouvrez le fichierMyName.kt
. Si vous ne disposez pas de ce fichier, créez-en un et appelez-leMyName.kt
. - Définissez une classe de données pour le nom et le surnom. Utilisez des chaînes vides comme valeurs par défaut.
data class MyName(var name: String = "", var nickname: String = "")
Étape 2 : Ajoutez des données à la mise en page
Dans le fichier activity_main.xml
, le nom est actuellement défini dans un TextView
à partir d'une ressource de chaîne. Vous devez remplacer la référence au nom par une référence aux données de la classe de données.
- Ouvrez
activity_main.xml
dans l'onglet Texte. - En haut de la mise en page, entre les balises
<layout>
et<LinearLayout>
, insérez une balise<data></data>
. C'est ici que vous associerez la vue aux données.
<data>
</data>
Dans les balises de données, vous pouvez déclarer des variables nommées qui contiennent une référence à une classe.
- Dans la balise
<data>
, ajoutez une balise<variable>
. - Ajoutez un paramètre
name
pour attribuer à la variable le nom"myName"
. Ajoutez un paramètretype
et définissez le type sur le nom complet de la classe de donnéesMyName
(nom du package + nom de la variable).
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
Désormais, au lieu d'utiliser la ressource de chaîne pour le nom, vous pouvez référencer la variable myName
.
- Remplacez
android:text="@string/name"
par le code ci-dessous.
@={}
est une directive permettant d'obtenir les données référencées entre accolades.
myName
fait référence à la variable myName
que vous avez définie précédemment, qui pointe vers la classe de données myName
et récupère la propriété name
de la classe.
android:text="@={myName.name}"
Étape 3 : Créez les données
Vous disposez maintenant d'une référence aux données dans votre fichier de mise en page. Vous allez maintenant créer les données.
- Ouvrez le fichier
MainActivity.kt
. - Au-dessus de
onCreate()
, créez une variable privée, également appeléemyName
par convention. Attribuez à la variable une instance de la classe de donnéesMyName
en transmettant le nom.
private val myName: MyName = MyName("Aleks Haecky")
- Dans
onCreate()
, définissez la valeur de la variablemyName
dans le fichier de mise en page sur la valeur de la variablemyName
que vous venez de déclarer. Vous ne pouvez pas accéder directement à la variable dans le code XML. Vous devez y accéder via l'objet de liaison.
binding.myName = myName
- Une erreur peut s'afficher, car vous devez actualiser l'objet de liaison après avoir apporté des modifications. Compilez votre application. L'erreur devrait disparaître.
Étape 4 : Utilisez la classe de données pour le pseudo dans la TextView
La dernière étape consiste à utiliser également la classe de données pour le pseudo dans TextView
.
- Ouvrez
activity_main.xml
. - Dans la vue de texte
nickname_text
, ajoutez une propriététext
. Référenceznickname
dans la classe de données, comme indiqué ci-dessous.
android:text="@={myName.nickname}"
- Dans
ActivityMain
, remplaceznicknameText.text = nicknameEdit.text.toString()
par le code permettant de définir le pseudo dans la variablemyName
.
myName?.nickname = nicknameEdit.text.toString()
Une fois le pseudo défini, vous souhaitez que votre code actualise l'UI avec les nouvelles données. Pour ce faire, vous devez invalider toutes les expressions de liaison afin qu'elles soient recréées avec les données correctes.
- Ajoutez
invalidateAll()
après avoir défini le pseudo afin que l'UI soit actualisée avec la valeur de l'objet de liaison mis à jour.
binding.apply {
myName?.nickname = nicknameEdit.text.toString()
invalidateAll()
...
}
- Compilez et exécutez votre application. Elle devrait fonctionner exactement comme avant.
Projet Android Studio : AboutMeDataBinding
Étapes à suivre pour utiliser la liaison de données afin de remplacer les appels à findViewById()
:
- Activez la liaison de données dans la section Android du fichier
build.gradle
:dataBinding { enabled = true }
- Utilisez
<layout>
comme vue racine dans votre mise en page XML. - Définissez une variable de liaison :
private lateinit var binding: ActivityMainBinding
- Créez un objet de liaison dans
MainActivity
, en remplaçantsetContentView
:binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Remplacez les appels à
findViewById()
par des références à la vue dans l'objet de liaison. Par exemple :findViewById<Button>(R.id.done_button) ⇒ binding.doneBu
tton
(dans l'exemple, le nom de la vue est généré en casse mixte à partir deid
de la vue dans le fichier XML).
Voici comment lier des vues à des données :
- Créez une classe de données pour vos données.
- Ajoutez un bloc
<data>
dans la balise<layout>
. - Définissez un
<variable>
avec un nom et un type correspondant à la classe de données.
<data>
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
</data>
- Dans
MainActivity
, créez une variable avec une instance de la classe de données. Exemple :private val myName: MyName = MyName("Aleks Haecky")
- Dans l'objet de liaison, définissez la variable sur celle que vous venez de créer :
binding.myName = myName
- Dans le code XML, définissez le contenu de la vue sur la variable que vous avez définie dans le bloc
<data>
. Utilisez la notation par points pour accéder aux données à l'intérieur de la classe de données.android:text="@={myName.name}"
Cours Udacity :
Documentation pour les développeurs Android :
- Bibliothèque Data Binding
- Classes de liaison générées
- Premiers pas avec la liaison de données
- Dispositions et expressions de liaison
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
Pourquoi limiter les appels explicites et implicites à findViewById()
?
- Chaque fois que
findViewById()
est appelé, il traverse la hiérarchie des vues. findViewById()
s'exécute sur le thread principal ou le thread de l'UI.- Ces appels peuvent ralentir l'interface utilisateur.
- Votre application est moins susceptible de planter.
Question 2
Comment décririez-vous la liaison de données ?
Par exemple, voici quelques exemples de ce que vous pourriez dire sur la liaison de données :
- L'idée principale de la liaison de données est de créer un objet qui connecte/mappe/lie deux informations distantes au moment de la compilation, afin que vous n'ayez pas à rechercher les données au moment de l'exécution.
- L'objet qui vous présente ces liaisons est appelé objet de liaison.
- L'objet de liaison est créé par le compilateur.
Question 3
Parmi les propositions suivantes, laquelle n'est PAS un avantage de la liaison de données ?
- Le code est plus court, et donc plus facile à lire et à gérer.
- Les données et les vues sont clairement séparées.
- Le système Android ne traverse la hiérarchie des vues qu'une seule fois pour obtenir chaque vue.
- L'appel de
findViewById()
génère une erreur de compilation. - Sûreté du typage pour accéder aux vues.
Question 4
Quelle est la fonction de la balise <layout>
?
- Vous l'enveloppez autour de votre vue racine dans la mise en page.
- Des liaisons sont créées pour toutes les vues d'une mise en page.
- Il désigne la vue de premier niveau dans une mise en page XML qui utilise la liaison de données.
- Vous pouvez utiliser la balise
<data>
à l'intérieur d'une balise<layout>
pour associer une variable à une classe de données.
Question 5
Quelle est la bonne méthode pour référencer des données liées dans la mise en page XML ?
android:text="@={myDataClass.property}"
android:text="@={myDataClass}"
android:text="@={myDataClass.property.toString()}"
android:text="@={myDataClass.bound_data.property}"
Passez à la leçon suivante :
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.