Android Kotlin Fundamentals 02.4: Data-binding Fundamentals

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.

Présentation

Dans les précédents ateliers de programmation de ce cours, vous avez utilisé la fonction findViewById() pour obtenir des références aux vues. Lorsque votre application présente des hiérarchies de vues complexes, la méthode findViewById() est coûteuse et ralentit l'application, car Android parcourt la hiérarchie des vues, à partir de la racine jusqu'à ce qu'elles trouvent la vue souhaitée. Heureusement, il y a une meilleure façon de procéder.

Pour définir les données dans des vues, vous avez utilisé des ressources de chaîne et défini les données de l'activité. Il serait plus efficace si les données avaient connaissance des données. Heureusement, c'est encore possible.

Dans cet atelier de programmation, vous allez apprendre à utiliser la liaison de données pour 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 être au fait:

  • Qu'est-ce qu'une activité et comment la configurer dans onCreate().
  • Créer une vue textuelle et définir le texte affiché
  • 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

  • Utiliser la bibliothèque de liaison de données pour éliminer les appels inefficaces vers findViewById().
  • Découvrez comment accéder aux données des applications directement à partir d'un fichier XML.

Objectifs de l'atelier

  • Modifiez une appli pour utiliser une liaison de données au lieu de findViewById(), et pour accéder aux données directement à partir des fichiers XML de mise en page.

Dans cet atelier de programmation, vous allez commencer avec l'application "AboutMe" (À propos de) et modifier l'application pour utiliser la liaison de données. Une fois l'opération terminée, l'application s'affiche exactement de la même façon.

Voici ce que fait l'application À propos de moi:

  • Lorsque l'utilisateur ouvre l'application, celle-ci affiche un nom, un champ permettant de saisir un pseudo, un bouton OK, une image suivi et un texte à faire défiler.
  • L'utilisateur peut saisir un pseudo, puis appuyez sur le bouton OK. Le champ et le bouton modifiables sont remplacés par une vue textuelle 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 sur 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 la fonction 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. Si votre application n'a que quelques vues, ce n'est pas un problème. Cependant, les applications de production peuvent présenter des dizaines de vues dans une mise en page, et même avec la meilleure conception, il y aura des vues imbriquées.

Prenons l'exemple d'une mise en page linéaire contenant une vue à faire défiler contenant une vue textuelle. Pour une hiérarchie grande ou profonde, la recherche d'une vue peut prendre suffisamment de temps pour ralentir l'application de façon visible. La mise en cache de vues peut être utile dans les variables, mais vous devez initialiser une variable pour chaque vue dans chaque espace de noms. Le nombre de vues et d'activités enregistrées peuvent aussi être élevés.

La première 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. Il s'agit de la 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.

La liaison de données présente les avantages suivants:

  • Le code est plus court, plus facile à lire et plus facile à gérer que le code findByView().
  • Les données et les vues sont clairement séparées. Cet avantage de la liaison des données devient de plus en plus important dans la suite de ce cours.
  • Le système Android ne traverse la hiérarchie des vues qu'une seule fois pour obtenir chaque vue et se produit au démarrage de l'application, et non au moment de l'exécution, lorsque l'utilisateur interagit avec l'application.
  • Vous pouvez accéder à des vues en toute sécurité. La sécurité par type 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 une liaison de données et utiliser une liaison de données 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 activer la liaison de données 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.

  1. Si vous ne possédez pas l'application À propos d'un atelier de programmation précédent, récupérez le code AboutMeDataBinding-Starter sur GitHub. Ouvrez-le dans Android Studio.
  2. Ouvrez le fichier build.gradle (Module: app).
  3. Dans la section android, ajoutez une section dataBinding avant l'accolade fermante et définissez enabled sur true.
dataBinding {
    enabled = true
}
  1. 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).
  2. Vous pouvez exécuter l'application, mais vous ne verrez aucune modification.

Étape 2: Modifiez le fichier de mise en page pour pouvoir l'utiliser avec la liaison de données

Pour utiliser une liaison de données, vous devez encapsuler votre mise en page XML avec une balise <layout>. Pour que la classe racine ne soit plus un groupe de vues, mais une mise en page contenant des groupes de vues et des vues. L'objet lié peut alors connaître la mise en page et les vues qu'elle contient.

  1. Ouvrez le fichier activity_main.xml.
  2. Accédez à l'onglet Text.
  3. Ajoutez <layout></layout> comme tag de niveau supérieur autour de <LinearLayout>.
<layout>
   <LinearLayout ... >
   ...
   </LinearLayout>
</layout>
  1. Sélectionnez Code > Reformat Code (Reformater le code) pour corriger le retrait du code.

    Les déclarations d'espace de noms associées à une mise en page doivent se trouver dans la balise la plus externe.
  1. Couper les déclarations d'espace de noms de <LinearLayout> et les coller dans la balise <layout>. Votre balise d'ouverture <layout> doit ressembler à ce qui suit, et la balise <LinearLayout> ne doit contenir que des propriétés de vue.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
  1. Créez et exécutez votre application pour vérifier que vous avez effectué cette opération correctement.

Étape 3: Créer un objet de liaison dans l'activité principale

Ajoutez une référence à l'objet lié dans l'activité principale afin de pouvoir l'utiliser pour accéder aux vues:

  1. Ouvrez le fichier MainActivity.kt.
  2. Avant onCreate(), créez une variable pour l'objet de liaison. Cette variable est généralement appelée binding.

    Le type debindingActivityMainBinding est créé par le compilateur pour cette activité principale. Le nom provient du nom du fichier de mise en page, à savoir activity_main + Binding.
private lateinit var binding: ActivityMainBinding
  1. Si Android Studio vous le demande, importez ActivityMainBinding. Si vous n'y êtes pas invité, cliquez sur ActivityMainBinding et appuyez sur Alt+Enter (Option+Enter sur un Mac) pour importer la classe manquante. Pour obtenir d'autres raccourcis clavier, consultez Raccourcis clavier.

    L'instruction import doit ressembler à celle affichée 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.
  • Il utilise la fonction setContentView() de la classe DataBindingUtil pour associer la mise en page activity_main à MainActivity. Cette fonction setContentView() assure également une configuration de la liaison de données pour les vues.
  1. Dans onCreate(), remplacez l'appel setContentView() par la ligne de code suivante.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
  1. Importez DataBindingUtil.
import androidx.databinding.DataBindingUtil

Étape 4: Utiliser l'objet de liaison pour remplacer tous les appels à findViewById()

Vous pouvez désormais remplacer tous les appels vers findViewById() par les références aux vues contenues 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 de la mise en page, en les convertissant en chameau. Ainsi, par exemple, done_button est doneButton dans l'objet lié, nickname_edit devient nicknameEdit et nickname_text devient nicknameText.

  1. Dans onCreate(), remplacez le code qui utilise findViewById() pour trouver le done_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

    Le code final pour définir l'écouteur de clics dans onCreate() doit se présenter comme suit :
binding.doneButton.setOnClickListener {
   addNickname(it)
}
  1. Effectuez la même opération pour tous les appels à findViewById() dans la fonction addNickname().
    Remplacez toutes les occurrences de findViewById<View>(R.id.id_view) par binding.idView. Procédez comme suit:
  • Supprimez les définitions des variables editText et nicknameTextView, ainsi que leurs appels vers findViewById(). Vous obtiendrez des erreurs.
  • Corrigez les erreurs en obtenant les vues nicknameText, nicknameEdit et doneButton à partir de l'objet binding plutôt que des variables (supprimées).
  • Remplacez view.visibility par binding.doneButton.visibility. L'utilisation de binding.doneButton à la place de la valeur view transmise permet de rendre le code plus cohérent.

    Le résultat suivant est généré:
binding.nicknameText.text = binding.nicknameEdit.text
binding.nicknameEdit.visibility = View.GONE
binding.doneButton.visibility = View.GONE
binding.nicknameText.visibility = View.VISIBLE
  • Aucune modification n'a été apportée. Si vous le souhaitez, vous pouvez désormais éliminer le paramètre view et mettre à jour toutes les utilisations de view pour utiliser binding.doneButton dans cette fonction.
  1. Le nicknameText nécessite un String et nicknameEdit.text est un Editable. Lorsque vous utilisez la liaison de données, vous devez convertir explicitement Editable en String.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
  1. Vous pouvez supprimer les importations grisées.
  2. 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
}
  1. Créez et exécutez votre application. Elle doit se présenter et fonctionner exactement comme avant.

Vous pouvez utiliser la liaison de données pour rendre une classe de données directement disponible dans une vue. Cette technique simplifie le code et est très utile pour gérer des cas plus complexes.

Dans cet exemple, au lieu de définir le nom et l'alias à l'aide de ressources de chaîne, vous créez une classe de données pour le nom et l'alias. Vous rendez la classe de données disponible pour la vue à l'aide de la liaison de données.

Étape 1: Créer la classe de données MyName

  1. Dans Android Studio, ouvrez le fichier MyName.kt dans le répertoire java. Si vous ne disposez pas de ce fichier, créez un fichier Kotlin et nommez-le MyName.kt.
  2. Définissez une classe de données pour le nom et le pseudo. 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.

  1. Ouvrez activity_main.xml dans l'onglet Text.
  2. En haut de la mise en page, insérez les balises <data></data> entre les balises <layout> et <LinearLayout>. C'est ici que vous allez connecter la vue aux données.
<data>
  
</data>

À l'intérieur des balises de données, vous pouvez déclarer des variables nommées qui contiennent une référence à une classe.

  1. Dans la balise <data>, ajoutez une balise <variable>.
  2. Ajoutez un paramètre name pour donner le nom "myName" à la variable. Ajoutez un paramètre type et définissez le type sur un nom complet de la classe de données MyName (nom du package + nom de la variable).
<variable
       name="myName"
       type="com.example.android.aboutme.MyName" />

Au lieu d'utiliser la ressource de chaîne pour le nom, vous pouvez faire référence à la variable myName.

  1. Remplacez android:text="@string/name" par le code ci-dessous.

@={} est une instruction pour 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 renvoie vers la classe de données myName et extrait la propriété name de la classe.

android:text="@={myName.name}"

Étape 3: Créer les données

Vous disposez désormais d'une référence aux données de votre fichier de mise en page. Créez ensuite les données réelles.

  1. Ouvrez le fichier MainActivity.kt.
  2. Au-dessus de onCreate(), créez une variable privée, également appelée myName par convention. Attribuez à la variable une instance de la classe de données MyName, en transmettant le nom.
private val myName: MyName = MyName("Aleks Haecky")
  1. Dans onCreate(), définissez la valeur de la variable myName dans le fichier de mise en page sur celle de la variable myName que vous venez de déclarer. Vous ne pouvez pas accéder directement à la variable dans le XML. Vous devez y accéder via l'objet lié.
binding.myName = myName
  1. Cela peut indiquer une erreur, car vous devez actualiser l'objet de liaison après avoir effectué des modifications. Une fois l'application créée, l'erreur devrait disparaître.

Étape 4: Utiliser la classe de données pour l'alias dans TextView

La dernière étape consiste également à utiliser la classe de données pour l'alias dans TextView.

  1. Ouvrez activity_main.xml.
  2. Dans la vue Texte nickname_text, ajoutez une propriété text. Référencez le nickname dans la classe de données, comme indiqué ci-dessous.
android:text="@={myName.nickname}"
  1. Dans ActivityMain, remplacez
    nicknameText.text = nicknameEdit.text.toString()
    par le code pour définir le pseudo dans la variable myName.
myName?.nickname = nicknameEdit.text.toString()

Une fois le pseudo défini, vous souhaitez que votre code actualise l'interface utilisateur 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 appropriées.

  1. Ajoutez invalidateAll() après avoir défini le pseudo pour que l'interface utilisateur soit actualisée avec la valeur dans l'objet de liaison mis à jour.
binding.apply {
   myName?.nickname = nicknameEdit.text.toString()
   invalidateAll()
   ...
}
  1. Après avoir compilé et exécuté votre application, elle devrait fonctionner exactement comme avant.

Projet Android Studio: AboutMeDataBinding

Procédure d'utilisation de la liaison de données pour remplacer les appels à findViewById() :

  1. Activez la liaison de données dans la section Android du fichier build.gradle:
    dataBinding { enabled = true }
  2. Utilisez <layout> comme vue racine dans votre mise en page XML.
  3. Définissez une variable de liaison :
    private lateinit var binding: ActivityMainBinding
  4. Créez un objet de liaison dans MainActivity, en remplaçant setContentView:
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
  5. Remplacez les appels vers findViewById() par des références à la vue dans l'objet de liaison. Par exemple:
    findViewById<Button>(R.id.done_button) ⇒ binding.doneButton
    (Dans cet exemple, le nom de la vue est généré à partir d'une recherche de chameaux à partir de la vue id dans le code XML.)

Procédure d'association de vues à des données:

  1. Créez une classe pour vos données.
  2. Ajoutez un bloc <data> dans la balise <layout>.
  3. Définissez un nom (<variable>) et un type de classe de données.
<data>
   <variable
       name="myName"
       type="com.example.android.aboutme.MyName" />
</data>
  1. Dans MainActivity, créez une variable avec une instance de la classe de données. Exemple :
    private val myName: MyName = MyName("Aleks Haecky")
  1. Dans l'objet liaison, définissez la variable sur celle que vous venez de créer:
    binding.myName = myName
  1. Dans le fichier XML, définissez le contenu de la vue sur la variable définie dans le bloc <data>. Utilisez la notation par point pour accéder aux données présentes dans la classe de données.
    android:text="@={myName.name}"

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

Pourquoi voulez-vous réduire les appels explicites et implicites vers findViewById() ?

  • Chaque fois que findViewById() est appelé, il parcourt la hiérarchie de la vue.
  • findViewById() s'exécute sur le thread principal ou UI.
  • Ces appels peuvent ralentir l'interface utilisateur.
  • Votre application est moins susceptible de planter.

Question 2

Comment décririez-vous votre liaison de données ?

Par exemple, voici quelques exemples de formulation:

  • Le but de la liaison de données est de créer un objet qui connecte/associe/lire deux informations distantes au moment de la compilation, de sorte que vous n'ayez pas à rechercher les données au moment de l'exécution.
  • L'objet qui vous renvoie 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, plus facile à lire et plus facile à 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écurité des types pour accéder aux vues

Question 4

Quelle est la fonction de la balise <layout> ?

  • Encapsulez-la 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 l'affichage de niveau supérieur dans une mise en page XML qui utilise une liaison de données.
  • Vous pouvez utiliser la balise <data> à l'intérieur d'une <layout> pour lier une variable à une classe de données.

Question 5

Quelle est la bonne façon de 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}"

Démarrez la leçon suivante: 3.1: créer un fragment.

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.