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<
) 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<String>"/>
<variable name="sparse" type="SparseArray<String>"/>
<variable name="map" type="Map<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 écouteurnull
à 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:onClick="@{handlers::onClickFriend}"/>
</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 vous 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:onClick="@{() -> 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:onClick="@{(view) -> 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:onClick="@{(theView) -> 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:onCheckedChanged="@{(cb, 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:onLongClick="@{(theView) -> 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:onClick="@{(v) -> 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<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.