Il linguaggio delle espressioni consente di scrivere espressioni per gestire gli eventi inviati in base alle visualizzazioni. La libreria di associazioni dati genera automaticamente le classi richieste per associare le viste nel layout agli oggetti dati.
I file di layout dell'associazione di dati sono leggermente diversi e iniziano con un tag principale di
layout
, seguito da un elemento data
e da un elemento principale view
. Questa visualizzazione
corrisponde all'elemento principale di un file di layout non vincolante. Il seguente codice
mostra un esempio di file di layout:
<?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 variabile user
in data
descrive una proprietà che può essere utilizzata in
questo layout:
<variable name="user" type="com.example.User" />
Le espressioni all'interno del layout vengono scritte nelle proprietà degli attributi utilizzando
Sintassi @{}
. Nell'esempio seguente,
Il testo di TextView
è impostato sul
Proprietà firstName
della variabile user
:
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}" />
Oggetti dati
Supponi di avere un oggetto normale per descrivere 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; } }
Questo tipo di oggetto include dati che non cambiano mai. È comune nelle app avere che vengono letti una volta sola e non cambiano più in seguito. È anche possibile usare un oggetto che segue un insieme di convenzioni, come l'utilizzo dei metodi della funzione di accesso il linguaggio di programmazione Java, come illustrato nell'esempio seguente:
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; } }
Dal punto di vista dell'associazione di dati, queste due classi sono equivalenti. La
l'espressione @{user.firstName}
utilizzata per
android:text
accede al campo firstName
nella classe precedente e
getFirstName()
nella seconda classe. Viene inoltre risolta
firstName()
, se questo metodo esiste.
Associazione dei dati
Viene generata una classe di associazione per ogni file di layout. Per impostazione predefinita, il nome
si basa sul nome del file di layout, convertito in formato Pascal, con
il suffisso Binding aggiunto. Ad esempio, il nome file del layout precedente è
activity_main.xml
, quindi la classe di associazione generata corrispondente è
ActivityMainBinding
.
Questa classe contiene tutte le associazioni delle proprietà del layout, ad esempio
la variabile user
alle visualizzazioni del layout e sa come assegnare i valori
le espressioni di associazione. Consigliamo di creare le associazioni durante il gonfiaggio
il layout, come mostrato nell'esempio seguente:
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); }
In fase di runtime, l'app mostra l'utente di test nella UI. In alternativa, puoi
ottenere la visualizzazione utilizzando
LayoutInflater
, come mostrato in
nell'esempio seguente:
Kotlin
val binding: ActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater())
Java
ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
Se utilizzi elementi di associazione di dati all'interno di un oggetto
Fragment
,
ListView
oppure
RecyclerView
potresti preferire l'utilizzo dell'adattatore
inflate()
delle classi di associazioni o
DataBindingUtil
, come
nell'esempio di codice che segue:
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);
Linguaggio di espressione
Funzionalità comuni
Il linguaggio delle espressioni assomiglia molto alle espressioni che si trovano nel codice gestito. Tu puoi utilizzare i seguenti operatori e parole chiave nel linguaggio delle espressioni:
- Matematica:
+ - / * %
- Concatenazione di stringhe:
+
- Logico:
&& ||
- Elemento binario:
& | ^
- Unaaria:
+ - ! ~
- Maiusc:
>> >>> <<
- Confronto:
== > < >= <=
(<
deve essere sottoposto a escape come<
) instanceof
- Raggruppamento:
()
- Valori letterali, ad esempio carattere, stringa, numerico,
null
- Cast
- Chiamate al metodo
- Accesso ai campi
- Accesso all'array:
[]
- Operatore ternario:
?:
Ecco alcuni esempi:
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
Operazioni mancanti
Le seguenti operazioni non sono presenti nella sintassi delle espressioni che puoi utilizzare nel codice gestito:
this
super
new
- Chiamata generica esplicita
Operatore di coalescenza null
L'operatore di coalescenza null (??
) sceglie l'operando sinistro se non è null
o quella a destra se la prima è null
:
android:text="@{user.displayName ?? user.lastName}"
Questo è funzionalmente equivalente a quanto segue:
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
Riferimenti proprietà
Un'espressione può fare riferimento a una proprietà di una classe utilizzando il formato seguente:
che è la stessa per campi, getter
ObservableField
oggetti:
android:text="@{user.lastName}"
Evita le eccezioni relative al puntatore nullo
Il codice di associazione dei dati generati verifica automaticamente i valori null
ed evita
tranne eccezioni del puntatore nullo. Ad esempio, nell'espressione @{user.name}
, se
user
è nullo. A user.name
viene assegnato il valore predefinito null
. Se
riferimento user.age
, dove l'età è di tipo int
, l'associazione di dati utilizza
il valore predefinito di 0
.
Visualizza riferimenti
Un'espressione può fare riferimento ad altre viste nel layout in base all'ID, utilizzando quanto segue: sintassi:
android:text="@{exampleText.text}"
Nell'esempio seguente, la vista TextView
fa riferimento a una vista EditText
in
lo stesso layout:
<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}"/>
Raccolte
Puoi accedere a raccolte comuni, come array, elenchi, elenchi sparsi e
utilizzando l'operatore []
per praticità.
<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]}"
Puoi anche fare riferimento a un valore nella mappa utilizzando la notazione object.key
. Per
esempio, puoi sostituire @{map[key]}
nell'esempio precedente con
@{map.key}
.
Valori letterali stringa
Puoi racchiudere il valore dell'attributo tra virgolette singole, in modo da utilizzare virgolette doppie nell'espressione, come illustrato nell'esempio seguente:
android:text='@{map["firstName"]}'
Puoi anche racchiudere il valore dell'attributo tra virgolette doppie. Nel farlo,
i valori letterali stringa devono essere racchiusi tra apici inversi `
, come mostrato
qui:
android:text="@{map[`firstName`]}"
Risorse
Un'espressione può fare riferimento alle risorse dell'app con la seguente sintassi:
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
Puoi valutare le stringhe di formato e le plurali fornendo i parametri:
android:text="@{@string/nameFormat(firstName, lastName)}"
android:text="@{@plurals/banana(bananaCount)}"
Puoi trasmettere riferimenti di proprietà e visualizzazione riferimenti come parametri delle risorse:
android:text="@{@string/example_resource(user.lastName, exampleText.text)}"
Quando una forma plurale accetta più parametri, passa tutti i parametri:
Have an orange
Have %d oranges
android:text="@{@plurals/orange(orangeCount, orangeCount)}"
Alcune risorse richiedono una valutazione del tipo esplicita, come mostrato di seguito tabella:
Tipo | Riferimento normale | Riferimento espressione |
---|---|---|
String[] |
@array |
@stringArray |
int[] |
@array |
@intArray |
TypedArray |
@array |
@typedArray |
Animator |
@animator |
@animator |
StateListAnimator |
@animator |
@stateListAnimator |
color int |
@color |
@color |
ColorStateList |
@color |
@colorStateList |
Gestione degli eventi
L'associazione di dati consente di scrivere gli eventi di gestione delle espressioni che vengono inviati da
le viste, ad esempio
onClick()
. I nomi degli attributi evento sono determinati dal nome del metodo listener,
con alcune eccezioni. Ad esempio:
View.OnClickListener
ha
un metodo onClick()
, quindi l'attributo per questo evento è android:onClick
.
Esistono alcuni gestori di eventi specializzati per l'evento click che richiedono una
diverso da android:onClick
per evitare conflitti. Puoi utilizzare lo
i seguenti attributi per evitare questo tipo di conflitti:
Classe | Autore impostazione listener | Attributo |
---|---|---|
SearchView |
setOnSearchClickListener(View.OnClickListener) |
android:onSearchClick |
ZoomControls |
setOnZoomInClickListener(View.OnClickListener) |
android:onZoomIn |
ZoomControls |
setOnZoomOutClickListener(View.OnClickListener) |
android:onZoomOut |
Puoi usare questi due meccanismi, descritti in dettaglio nelle sezioni seguire per gestire un evento:
- Riferimenti ai metodi: nelle espressioni, puoi
metodi di riferimento conformi alla firma del metodo listener. Quando
un'espressione restituisce un riferimento a un metodo, l'associazione di dati racchiude il metodo
l'oggetto riferimento e proprietario in un listener e imposta tale listener nel
vista target. Se l'espressione restituisce
null
, l'associazione di dati non crea un listener e imposta invece un listenernull
. - Associazioni listener: si tratta di espressioni lambda che vengono valutati quando si verifica l'evento. L'associazione di dati crea sempre , che imposta nella vista. Quando l'evento viene inviato, listener valuta l'espressione lambda.
Riferimenti ai metodi
Puoi associare direttamente gli eventi ai metodi di gestore, in modo simile
assegna
android:onClick
a un
in un'attività. Un vantaggio rispetto alla
L'attributo onClick
View
è che
viene elaborata al momento della compilazione. Quindi, se il metodo non esiste o
la firma non è corretta, ricevi un errore durante la compilazione.
La principale differenza tra i riferimenti ai metodi e le associazioni listener è che il valore l'implementazione effettiva del listener viene creata quando vengono associati i dati, non quando . Se preferisci valutare l'espressione quando l'evento Usa le associazioni di ascoltatori.
Per assegnare un evento al relativo gestore, utilizza una normale espressione di associazione, con che rappresenta il nome del metodo da chiamare. Considera ad esempio il seguente esempio Oggetto dati di layout:
Kotlin
class MyHandlers { fun onClickFriend(view: View) { ... } }
Java
public class MyHandlers { public void onClickFriend(View view) { ... } }
L'espressione di associazione può assegnare il listener di clic per una vista al
onClickFriend()
, come segue:
<?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>
Associazioni di listener
Le associazioni di listener sono espressioni di associazione che vengono eseguite quando si verifica un evento. Loro sono simili ai riferimenti ai metodi, ma consentono di eseguire associazioni di dati arbitrarie le espressioni regolari. Questa funzionalità è disponibile con il plug-in Android Gradle per Gradle versione 2.0 e successive.
Nei riferimenti al metodo, i parametri del metodo devono corrispondere a quelli del
il listener di eventi. Nelle associazioni di listener, solo il valore restituito deve corrispondere al valore
valore restituito previsto del listener, a meno che non sia previsto void
. Per
ad esempio, considera la seguente classe presentatore che ha un onSaveClick()
:
Kotlin
class Presenter { fun onSaveClick(task: Task){} }
Java
public class Presenter { public void onSaveClick(Task task){} }
Puoi associare l'evento di clic al metodo onSaveClick()
nel seguente modo:
<?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>
Quando si utilizza un callback in un'espressione, l'associazione di dati crea automaticamente la listener necessario e lo registra per l'evento. Quando la vista attiva l'associazione di dati valuta l'espressione specificata. Come per l'associazione normale di associazione di dati, ottieni la sicurezza null e dei thread dell'associazione di dati mentre È in corso la valutazione delle espressioni listener.
Nell'esempio precedente, il parametro view
passato a onClick(View)
non è definito. Le associazioni di listener offrono due opzioni per i parametri listener:
puoi ignorare tutti i parametri del metodo o nominarli tutti. Se preferisci
per assegnare un nome ai parametri, puoi utilizzarli nell'espressione. Ad esempio,
può scrivere l'espressione precedente come segue:
android:onClick="@{(view) -> presenter.onSaveClick(task)}"
Per utilizzare il parametro nell'espressione, procedi nel seguente modo:
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)}"
Inoltre, puoi utilizzare un'espressione lambda con più di un parametro:
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)}" />
Se l'evento che stai ascoltando restituisce un valore di tipo diverso da void
, il tuo
devono restituire lo stesso tipo di valore. Ad esempio, se vuoi
di ascoltare il tocco e di blocco (clic lungo), l'espressione deve restituire un
booleano.
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)}"
Se l'espressione non può essere valutata a causa degli oggetti null
, l'associazione di dati viene restituita
il valore predefinito per il tipo in questione, ad esempio null
per i tipi di riferimento, 0
per
int
o false
per boolean
.
Se devi utilizzare un'espressione con un predicato, ad esempio un
ternario, puoi utilizzare void
come simbolo:
android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"
Evita listener complessi
Le espressioni listener sono potenti e possono semplificare la lettura del codice. Il giorno Dall'altra parte, i listener che contengono espressioni complesse rendono i tuoi layout più rigidi da leggere e gestire. Mantieni le espressioni semplici come la trasmissione dei dati disponibili dall'interfaccia utente al metodo di callback. Implementa qualsiasi logica di business all'interno metodo di callback richiamato dall'espressione listener.
Importazioni, variabili e include
La libreria di associazioni di dati offre funzionalità quali importazioni, variabili e inclusi. Le importazioni consentono di creare classi di facile riferimento all'interno dei file di layout. Le variabili consentono di descrivere una proprietà che può essere utilizzata nelle espressioni di associazione. Ti consentono di riutilizzare layout complessi nella tua app.
Importazioni
Le importazioni ti consentono di fare riferimento alle classi all'interno del file di layout, come nel codice gestito.
Puoi utilizzare zero o più elementi import
all'interno dell'elemento data
. La
L'esempio di codice riportato di seguito importa la classe View
nel file di layout:
<data>
<import type="android.view.View"/>
</data>
L'importazione della classe View
consente di farvi riferimento dalle espressioni di associazione.
L'esempio seguente mostra come fare riferimento
VISIBLE
e
costanti GONE
della 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 del tipo
In caso di conflitti di nomi di classi, puoi rinominare una delle classi in un
alias. L'esempio seguente rinomina la classe View
nel
Pacchetto com.example.real.estate
per Vista
:
<import type="android.view.View"/>
<import type="com.example.real.estate.View"
alias="Vista"/>
Puoi quindi utilizzare Vista
per fare riferimento a com.example.real.estate.View
e View
per fare riferimento a android.view.View
all'interno del file di layout.
Importa altri corsi
Puoi utilizzare i tipi importati come riferimenti al tipo in variabili ed espressioni. La
l'esempio seguente mostra User
e List
utilizzati come tipo di variabile:
<data>
<import type="com.example.User"/>
<import type="java.util.List"/>
<variable name="user" type="User"/>
<variable name="userList" type="List<User>"/>
</data>
Puoi utilizzare i tipi importati per trasmettere parte di un'espressione. Le seguenti
ad esempio trasmette la proprietà connection
a un tipo di User
:
<TextView
android:text="@{((User)(user.connection)).lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Puoi utilizzare i tipi importati anche quando fai riferimento a campi e metodi statici in
le espressioni regolari. Il seguente codice importa la classe e i riferimenti MyStringUtils
il suo metodo 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"/>
Proprio come nel codice gestito, java.lang.*
viene importato automaticamente.
Variabili
Puoi utilizzare più elementi variable
all'interno dell'elemento data
. Ciascuna
L'elemento variable
descrive una proprietà che può essere impostata sul layout da utilizzare
nelle espressioni di associazione all'interno del file di layout. L'esempio seguente dichiara
le variabili user
, image
e 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>
I tipi di variabili vengono esaminati al momento della compilazione, pertanto se una variabile implementa
Observable
o è un
raccolta osservabile,
che deve riflettersi nel tipo. Se la variabile è una classe base o un'interfaccia
che non implementa l'interfaccia Observable
, le variabili non sono
osservati.
Quando sono presenti file di layout diversi per varie configurazioni (ad esempio, orizzontale o verticale), le variabili vengono combinate. Non devono esserci definizioni di variabili in conflitto tra questi file di layout.
La classe di associazione generata ha un setter e un getter per ciascuno dei
come la codifica one-hot
delle variabili categoriche. Le variabili assumono i valori predefiniti del codice gestito fino al setter
è chiamato: null
per i tipi di riferimento, 0
per int
, false
per
boolean
e così via.
Viene generata una variabile speciale denominata context
da utilizzare nelle espressioni di associazione
dell'oggetto o eliminare definitivamente una
versione archiviata, in base alle necessità. Il valore di context
è
Context
dal pannello della vista principale
getContext()
. La
La variabile context
è sostituita da una dichiarazione di variabile esplicita con questa
.
Include
Puoi trasferire le variabili nell'associazione di un layout incluso dalla
utilizzando lo spazio dei nomi dell'app e il nome della variabile in un attributo. La
l'esempio seguente mostra le variabili user
incluse in name.xml
e
contact.xml
file di layout:
<?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>
L'associazione di dati non supporta l'inclusione come elemento secondario diretto di un elemento di unione. Ad esempio, il seguente layout non è supportato:
<?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>
Risorse aggiuntive
Per saperne di più sull'associazione di dati, consulta le seguenti risorse aggiuntive.