Dispositions et expressions de liaison

Le langage d'expression vous permet d'écrire des expressions qui gèrent les événements envoyés par nombre de vues. La bibliothèque Data Binding génère automatiquement les classes requises pour lier les vues de la mise en page à vos objets de données.

Les fichiers de mise en page de liaison de données sont légèrement différents et commencent par une balise racine de layout, suivi d'un élément data et d'un élément racine view. Cette vue correspond à l'élément racine d'un fichier de mise en page sans liaison. Le code suivant affiche un exemple de fichier de mise en page:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>

La variable user dans data décrit une propriété pouvant être utilisée dans cette mise en page:

<variable name="user" type="com.example.User" />

Les expressions de la mise en page sont écrites dans les propriétés de l'attribut à l'aide de la méthode Syntaxe @{}. Dans l'exemple suivant, TextView est défini sur la Propriété firstName de la variable user:

<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{user.firstName}" />

Objets de données

Supposons que vous disposiez d'un objet brut pour décrire l'entité User:

Kotlin

data class User(val firstName: String, val lastName: String)

Java


public class User {
  public final String firstName;
  public final String lastName;
  public User(String firstName, String lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
  }
}

Ce type d'objet contient des données qui ne changent jamais. Il est courant dans les applications d’avoir des données qui sont lues une fois et ne changent jamais par la suite. Il est également possible d'utiliser un objet qui suit un ensemble de conventions, comme l'utilisation de méthodes d'accesseur dans le langage de programmation Java, comme illustré dans l'exemple suivant:

Kotlin

// Not applicable in Kotlin.
data class User(val firstName: String, val lastName: String)

Java

public class User {
  private final String firstName;
  private final String lastName;
  public User(String firstName, String lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
  }
  public String getFirstName() {
      return this.firstName;
  }
  public String getLastName() {
      return this.lastName;
  }
}

Du point de vue de la liaison de données, ces deux classes sont équivalentes. La l'expression @{user.firstName} utilisée pour android:text accède au champ firstName dans l'ancienne classe et au getFirstName() dans cette dernière classe. Elle est également résolue en firstName(), si cette méthode existe.

Liaison de données

Une classe de liaison est générée pour chaque fichier de mise en page. Par défaut, le nom est basée sur le nom du fichier de mise en page, converti en casse Pascal, avec le suffixe Binding qui lui a été ajouté. Par exemple, le nom de fichier de mise en page précédent est activity_main.xml : la classe de liaison générée correspondante est donc ActivityMainBinding

Cette classe contient toutes les liaisons des propriétés de mise en page (par exemple, La variable user aux vues de la mise en page et sait comment attribuer des valeurs pour les expressions de liaison. Nous vous recommandons de créer les liaisons la mise en page, comme illustré dans l'exemple suivant:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val binding: ActivityMainBinding = DataBindingUtil.setContentView(
            this, R.layout.activity_main)

    binding.user = User("Test", "User")
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
   User user = new User("Test", "User");
   binding.setUser(user);
}

Au moment de l'exécution, l'application affiche l'utilisateur Test dans l'interface utilisateur. Vous pouvez également obtenir la vue à l'aide d'un LayoutInflater, comme indiqué dans les l'exemple suivant:

Kotlin

val binding: ActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater())

Java

ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());

Si vous utilisez des éléments de liaison de données dans un Fragment ListView ou RecyclerView vous pouvez utiliser l'adaptateur inflate() des classes de liaisons ou de la classe DataBindingUtil, en tant que illustré dans l'exemple de code suivant:

Kotlin

val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false)
// or
val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)

Java

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
// or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

Langage d'expression

Fonctionnalités communes

Le langage d'expression ressemble beaucoup aux expressions présentes dans le code géré. Toi peuvent utiliser les opérateurs et mots clés suivants dans le langage de l'expression:

  • Mathématique: + - / * %
  • Concaténation de chaînes: +
  • Logique: && ||
  • Binaire: & | ^
  • Unaire: + - ! ~
  • Maj: >> >>> <<
  • Comparaison: == > < >= <= (< doit être échappé en tant que &lt;)
  • instanceof
  • Groupement : ()
  • Littéraux tels que caractère, chaîne, numérique, null
  • Caster
  • Appels de méthode
  • Accès aux champs
  • Accès au tableau: []
  • Opérateur ternaire: ?:

Voici quelques exemples :

android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'

Opérations manquantes

Les opérations suivantes sont manquantes dans la syntaxe d'expression que vous pouvez utiliser dans du code géré:

  • this
  • super
  • new
  • Appel générique explicite

Opérateur de fusionnement nul

L'opérateur de fusionnement nul (??) choisit l'opérande de gauche s'il n'est pas null ou "right" si la première est null:

android:text="@{user.displayName ?? user.lastName}"

D'un point de vue fonctionnel, cette méthode est équivalente à celle-ci:

android:text="@{user.displayName != null ? user.displayName : user.lastName}"

Références de propriété

Une expression peut référencer une propriété d'une classe à l'aide du format suivant : qui est le même pour les champs, les getters et ObservableField Objets:

android:text="@{user.lastName}"

Éviter les exceptions de pointeur nul

Le code de liaison de données généré vérifie automatiquement les valeurs null et évite les exceptions de pointeur nul. Par exemple, dans l'expression @{user.name}, si user est nul, user.name reçoit sa valeur par défaut de null. Si vous référence user.age, où l'âge est de type int, la liaison de données utilise le la valeur par défaut de 0.

Afficher les références

Une expression peut référencer d'autres vues de la mise en page par ID, à l'aide du code suivant : syntaxe:

android:text="@{exampleText.text}"

Dans l'exemple suivant, la vue TextView fait référence à une vue EditText dans la même mise en page:

<EditText
    android:id="@+id/example_text"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"/>
<TextView
    android:id="@+id/example_output"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{exampleText.text}"/>

Collections

Vous pouvez accéder aux collections courantes telles que les tableaux, les listes, les listes creuses et en utilisant l'opérateur [] pour plus de commodité.

<data>
    <import type="android.util.SparseArray"/>
    <import type="java.util.Map"/>
    <import type="java.util.List"/>
    <variable name="list" type="List&lt;String>"/>
    <variable name="sparse" type="SparseArray&lt;String>"/>
    <variable name="map" type="Map&lt;String, String>"/>
    <variable name="index" type="int"/>
    <variable name="key" type="String"/>
</data>
...
android:text="@{list[index]}"
...
android:text="@{sparse[index]}"
...
android:text="@{map[key]}"

Vous pouvez également faire référence à une valeur de la carte en utilisant la notation object.key. Pour vous pouvez remplacer @{map[key]} de l'exemple précédent par @{map.key}

Littéraux de chaîne

Vous pouvez placer la valeur de l'attribut entre guillemets simples, ce qui vous permet d'utiliser Des guillemets doubles dans l'expression, comme illustré dans l'exemple suivant:

android:text='@{map["firstName"]}'

Vous pouvez également utiliser des guillemets doubles pour délimiter la valeur de l'attribut. Ce faisant, Les littéraux de chaîne doivent être entourés d'accents graves `, comme indiqué ici:

android:text="@{map[`firstName`]}"

Ressources

Une expression peut référencer des ressources d'application avec la syntaxe suivante:

android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"

Vous pouvez évaluer les chaînes de format et les pluriels en fournissant des paramètres:

android:text="@{@string/nameFormat(firstName, lastName)}"
android:text="@{@plurals/banana(bananaCount)}"

Vous pouvez transmettre des références de propriété et afficher comme paramètres de ressource:

android:text="@{@string/example_resource(user.lastName, exampleText.text)}"

Lorsqu'un pluriel accepte plusieurs paramètres, transmettez tous les paramètres:


  Have an orange
  Have %d oranges

android:text="@{@plurals/orange(orangeCount, orangeCount)}"

Certaines ressources nécessitent une évaluation de type explicite, comme illustré ci-dessous tableau:

Type Référence normale Référence d'expression
String[] @array @stringArray
int[] @array @intArray
TypedArray @array @typedArray
Animator @animator @animator
StateListAnimator @animator @stateListAnimator
color int @color @color
ColorStateList @color @colorStateList

Gestion des événements

La liaison de données vous permet d'écrire des expressions qui gèrent les événements envoyés depuis les vues (par exemple, onClick() . Les noms des attributs d'événement sont déterminés par le nom de la méthode d'écouteur, à quelques exceptions près. Par exemple : View.OnClickListener a Une méthode onClick(). L'attribut de cet événement est donc android:onClick.

Certains gestionnaires d'événements spécialisés pour l'événement de clic requièrent une autre que android:onClick pour éviter tout conflit. Vous pouvez utiliser les attributs suivants pour éviter ce type de conflit:

Classe Setter de l'écouteur Attribut
SearchView setOnSearchClickListener(View.OnClickListener) android:onSearchClick
ZoomControls setOnZoomInClickListener(View.OnClickListener) android:onZoomIn
ZoomControls setOnZoomOutClickListener(View.OnClickListener) android:onZoomOut

Vous pouvez utiliser ces deux mécanismes, décrits en détail dans les sections pour gérer un événement:

  • Références de méthode: dans vos expressions, vous pouvez des méthodes de référence conformes à la signature de la méthode d'écouteur. Quand ? une expression renvoie une référence de méthode, la liaison de données encapsule la méthode référence et propriétaire dans un écouteur et définit cet écouteur sur le vue cible. Si l'expression renvoie la valeur null, la liaison de données n'effectue pas Créez un écouteur et définissez un écouteur null à la place.
  • Listener bindings: il s'agit d'expressions lambda qui sont évaluées lorsque l'événement se produit. La liaison de données crée toujours qu'il définit sur la vue. Lorsque l'événement est déclenché, L'écouteur évalue l'expression lambda.

Références de méthode

Vous pouvez lier des événements directement aux méthodes de gestionnaire, de la même manière que vous pouvez attribuer android:onClick en dans une activité. L'un des avantages par rapport L'attribut onClick de View est que est traitée au moment de la compilation. Si la méthode n'existe pas signature est incorrecte, vous recevez une erreur au moment de la compilation.

La principale différence entre les références de méthode et les expressions "listener binding" est que l'implémentation réelle de l'écouteur est créée lorsque les données sont liées, et non lorsque le est déclenché. Si vous préférez évaluer l'expression lorsque l'événement utilisez des liaisons d'écouteur.

Pour attribuer un événement à son gestionnaire, utilisez une expression de liaison normale, avec la propriété value est le nom de la méthode à appeler. Prenons l'exemple suivant : objet de données de mise en page:

Kotlin

class MyHandlers {
    fun onClickFriend(view: View) { ... }
}

Java

public class MyHandlers {
    public void onClickFriend(View view) { ... }
}

L'expression de liaison peut attribuer l'écouteur de clics d'une vue au paramètre onClickFriend(), comme suit:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="handlers" type="com.example.MyHandlers"/>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"
           android:
   </LinearLayout>
</layout>

Expressions "listener binding"

Les expressions "listener binding" sont des expressions de liaison qui s'exécutent lorsqu'un événement se produit. Ils sont semblables aux références de méthodes, mais elles permettent d'exécuter une liaison de données arbitraire . Cette fonctionnalité est disponible avec le plug-in Android Gradle pour Gradle versions 2.0 et ultérieures.

Dans les références de méthode, les paramètres de la méthode doivent correspondre à ceux de l'écouteur d'événements. Dans les expressions "listener binding", seule votre valeur renvoyée doit correspondre à valeur de retour attendue de l'écouteur, sauf s'il attend void. Pour Prenons l'exemple de la classe de présentateur suivante, qui a un onSaveClick() méthode:

Kotlin

class Presenter {
    fun onSaveClick(task: Task){}
}

Java

public class Presenter {
    public void onSaveClick(Task task){}
}

Vous pouvez lier l'événement de clic à la méthode onSaveClick() comme suit:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="task" type="com.android.example.Task" />
        <variable name="presenter" type="com.android.example.Presenter" />
    </data>
    <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
        <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
        android: -> presenter.onSaveClick(task)}" />
    </LinearLayout>
</layout>

Lorsqu'un rappel est utilisé dans une expression, la liaison de données crée automatiquement le l'écouteur nécessaire et l'enregistre pour l'événement. Lorsque la vue déclenche la liaison de données évalue l'expression donnée. Comme pour la liaison standard vous obtenez la sécurité nulle et la sécurité des threads de la liaison de données, tandis que ces expressions d'écouteur sont en cours d'évaluation.

Dans l'exemple précédent, le paramètre view transmis à onClick(View) n'est pas définie. Les expressions "listener binding" offrent deux options pour les paramètres d'écouteur: vous pouvez ignorer tous les paramètres de la méthode ou tous les nommer. Si vous préférez pour nommer les paramètres, vous pouvez les utiliser dans votre expression. Par exemple : peut écrire l'expression qui précède comme suit:

android: -> presenter.onSaveClick(task)}"

Si vous souhaitez utiliser le paramètre dans l'expression, procédez comme suit:

Kotlin

class Presenter {
    fun onSaveClick(view: View, task: Task){}
}

Java

public class Presenter {
    public void onSaveClick(View view, Task task){}
}

android: -> presenter.onSaveClick(theView, task)}"

Vous pouvez également utiliser une expression lambda avec plusieurs paramètres:

Kotlin

class Presenter {
    fun onCompletedChanged(task: Task, completed: Boolean){}
}

Java

public class Presenter {
    public void onCompletedChanged(Task task, boolean completed){}
}

<CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
      android: isChecked) -> presenter.completeChanged(task, isChecked)}" />

Si l'événement que vous écoutez renvoie une valeur de type autre que void, votre les expressions doivent également renvoyer le même type de valeur. Par exemple, si vous souhaitez d’écouter l’appui et l'événement de préservation (clic long), votre expression doit renvoyer une Booléen.

Kotlin

class Presenter {
    fun onLongClick(view: View, task: Task): Boolean { }
}

Java

public class Presenter {
    public boolean onLongClick(View view, Task task) { }
}

android: -> presenter.onLongClick(theView, task)}"

Si l'expression ne peut pas être évaluée en raison d'objets null, la liaison de données renvoie la valeur par défaut pour ce type, par exemple null pour les types de référence, 0 pour int ou false pour boolean.

Si vous devez utiliser une expression avec un prédicat, par exemple, ternaire, vous pouvez utiliser void comme symbole:

android: -> v.isVisible() ? doSomething() : void}"

Éviter les écouteurs complexes

Les expressions d'écouteur sont performantes et peuvent faciliter la lecture de votre code. Le En revanche, les écouteurs contenant des expressions complexes rendent vos mises en page plus difficiles. à lire et à gérer. Simplifiez vos expressions en transmettant les données disponibles de votre UI à votre méthode de rappel. Implémentez une logique métier à l'intérieur de de rappel que vous appelez à partir de l'expression d'écouteur.

Importations, variables et inclusions

La bibliothèque Data Binding fournit des fonctionnalités telles que des importations, des variables et inclut. Les importations permettent de créer des classes faciles à référencer dans vos fichiers de mise en page. Les variables vous permettent de décrire une propriété pouvant être utilisée dans des expressions de liaison. Elles vous permettent de réutiliser des mises en page complexes dans votre application.

Importations

Les importations vous permettent de référencer des classes dans votre fichier de mise en page, comme dans le code géré. Vous pouvez utiliser zéro, un ou plusieurs éléments import dans l'élément data. La L'exemple de code suivant importe la classe View dans le fichier de mise en page:

<data>
    <import type="android.view.View"/>
</data>

Importer la classe View vous permet de la référencer à partir de vos expressions de liaison. L'exemple suivant montre comment référencer VISIBLE et Constantes GONE de la classe View:

<TextView
   android:text="@{user.lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

Alias de type

En cas de conflit de noms de classe, vous pouvez renommer l'une des classes un alias. L'exemple suivant renomme la classe View dans le Package com.example.real.estate vers Vista:

<import type="android.view.View"/>
<import type="com.example.real.estate.View"
        alias="Vista"/>

Vous pouvez ensuite utiliser Vista pour référencer com.example.real.estate.View et View pour référencer android.view.View dans le fichier de mise en page.

Importer d'autres classes

Vous pouvez utiliser des types importés comme références de type dans les variables et les expressions. La L'exemple suivant montre User et List utilisés comme type de variable:

<data>
    <import type="com.example.User"/>
    <import type="java.util.List"/>
    <variable name="user" type="User"/>
    <variable name="userList" type="List&lt;User>"/>
</data>
.

Vous pouvez utiliser les types importés pour caster une partie d'une expression. Les éléments suivants : Dans cet exemple, la propriété connection est convertie en un type User:

<TextView
   android:text="@{((User)(user.connection)).lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

Vous pouvez également utiliser des types importés pour référencer des champs et des méthodes statiques dans . Le code suivant importe la classe MyStringUtils et les références sa méthode capitalize:

<data>
    <import type="com.example.MyStringUtils"/>
    <variable name="user" type="com.example.User"/>
</data>
…
<TextView
   android:text="@{MyStringUtils.capitalize(user.lastName)}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

Tout comme dans le code géré, java.lang.* est importé automatiquement.

Variables

Vous pouvez utiliser plusieurs éléments variable dans l'élément data. Chaque L'élément variable décrit une propriété pouvant être définie sur la mise en page à utiliser. dans les expressions de liaison du fichier de mise en page. L'exemple suivant déclare les variables user, image et note:

<data>
    <import type="android.graphics.drawable.Drawable"/>
    <variable name="user" type="com.example.User"/>
    <variable name="image" type="Drawable"/>
    <variable name="note" type="String"/>
</data>

Les types de variables sont inspectés au moment de la compilation, donc si une variable implémente Observable ou est un collection observable, qui doit être reflétée dans le type. Si la variable est une classe ou une interface de base qui n'implémente pas l'interface Observable, les variables ne sont pas observée.

Lorsqu'il existe différents fichiers de mise en page pour différentes configurations (par exemple, paysage ou portrait), les variables sont combinées. Il ne doit pas y avoir des définitions de variables en conflit entre ces fichiers de mise en page.

La classe de liaison générée comporte un setter et un getter pour chacun des éléments décrits variables. Les variables prennent les valeurs du code géré par défaut jusqu'à ce que le setter est appelé : null pour les types de référence, 0 pour int, false pour boolean, etc.

Une variable spéciale nommée context est générée pour être utilisée dans les expressions de liaison si nécessaire. La valeur de context est la Context à partir de l'objet getContext(). La La variable context est remplacée par une déclaration de variable explicite par cette son nom.

Comprend

Vous pouvez transmettre des variables à la liaison d'une mise en page incluse à partir du fichier en utilisant l'espace de noms de l'application et le nom de la variable dans un attribut. La L'exemple suivant montre les variables user incluses des name.xml et Fichiers de mise en page contact.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </LinearLayout>
</layout>

La liaison de données n'est pas compatible avec une inclusion en tant qu'enfant direct d'un élément de fusion. Par exemple, la mise en page suivante n'est pas acceptée:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <merge><!-- Doesn't work -->
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </merge>
</layout>

Ressources supplémentaires

Pour en savoir plus sur la liaison de données, consultez les ressources supplémentaires suivantes.

Exemples

Ateliers de programmation

Articles de blog