Android
Bibliothèque de liaison de données
Recherche…
Remarques
Installer
Avant d'utiliser la liaison de données, vous devez activer le plug-in dans votre build.gradle
.
android {
....
dataBinding {
enabled = true
}
}
Remarque: la liaison de données a été ajoutée au plug-in Android Gradle dans la version 1.5.0
Noms de classe de liaison
Le plug-in de liaison de données génère un nom de classe de liaison en convertissant le nom de fichier de votre mise en page en cas Pascal et en ajoutant "Liaison" à la fin. Ainsi, item_detail_activity.xml
générera une classe nommée ItemDetailActivityBinding
.
Ressources
Liaison de texte de base
Gradle (Module: app) Configuration
android {
....
dataBinding {
enabled = true
}
}
Modèle de données
public class Item {
public String name;
public String description;
public Item(String name, String description) {
this.name = name;
this.description = description;
}
}
XML de mise en page
La première étape consiste à encapsuler votre mise en page dans une <layout>
, à ajouter un élément <data>
et à ajouter un élément <variable>
à votre modèle de données.
Vous pouvez ensuite lier des attributs XML à des champs du modèle de données à l'aide de @{model.fieldname}
, où model
est le nom de la variable et fieldname
le champ @{model.fieldname}
vous souhaitez accéder.
item_detail_activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="com.example.Item"/>
</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="@{item.name}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.description}"/>
</LinearLayout>
</layout>
Pour chaque fichier de disposition XML correctement configuré avec des liaisons, le plugin Android Gradle génère une classe correspondante: bindings. Comme nous avons une mise en page nommée item_detail_activity , la classe de liaison générée correspondante s'appelle ItemDetailActivityBinding
.
Cette liaison peut alors être utilisée dans une activité comme celle-ci:
public class ItemDetailActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ItemDetailActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.item_detail_activity);
Item item = new Item("Example item", "This is an example item.");
binding.setItem(item);
}
}
Liaison avec une méthode d'accesseur
Si votre modèle a des méthodes privées, la bibliothèque de liaison de données vous permet toujours d'y accéder dans votre vue sans utiliser le nom complet de la méthode.
Modèle de données
public class Item {
private String name;
public String getName() {
return name;
}
}
XML de mise en page
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="com.example.Item"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Since the "name" field is private on our data model,
this binding will utilize the public getName() method instead. -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>
</LinearLayout>
</layout>
Cours de référencement
Modèle de données
public class Item {
private String name;
public String getName() {
return name;
}
}
XML de mise en page
Vous devez importer les classes référencées, comme vous le feriez en Java.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
<variable name="item" type="com.example.Item"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- We reference the View class to set the visibility of this TextView -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"
android:visibility="@{item.name == null ? View.VISIBLE : View.GONE"/>
</LinearLayout>
</layout>
Remarque: Le package java.lang.*
Est importé automatiquement par le système. (La même chose est faite par JVM
pour Java
)
Liaison de données en fragment
Modèle de données
public class Item {
private String name;
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
}
XML de mise en page
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="com.example.Item"/>
</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="@{item.name}"/>
</LinearLayout>
</layout>
Fragment
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
FragmentTest binding = DataBindingUtil.inflate(inflater, R.layout.fragment_test, container, false);
Item item = new Item();
item.setName("Thomas");
binding.setItem(item);
return binding.getRoot();
}
Liaison de données bidirectionnelle intégrée
La liaison de données bidirectionnelle prend en charge les attributs suivants:
Élément | Propriétés |
---|---|
AbsListView | android:selectedItemPosition |
CalendarView | android:date |
CompoundButton | android:checked |
DatePicker |
|
EditText | android:text |
NumberPicker | android:value |
RadioGroup | android:checkedButton |
RatingBar | android:rating |
SeekBar | android:progress |
TabHost | android:currentTab |
TextView | android:text |
TimePicker |
|
ToggleButton | android:checked |
Switch | android:checked |
Usage
<layout ...>
<data>
<variable type="com.example.myapp.User" name="user"/>
</data>
<RelativeLayout ...>
<EditText android:text="@={user.firstName}" .../>
</RelativeLayout>
</layout>
Notez que l'expression Binding @={}
a un =
supplémentaire , nécessaire pour la liaison bidirectionnelle . Il n'est pas possible d'utiliser des méthodes dans des expressions de liaison bidirectionnelles.
Liaison de données dans l'adaptateur RecyclerView
Il est également possible d'utiliser la liaison de données dans votre adaptateur RecyclerView
.
Modèle de données
public class Item {
private String name;
public String getName() {
return name;
}
}
Mise en page XML
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>
Classe d'adaptateur
public class ListItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Activity host;
private List<Item> items;
public ListItemAdapter(Activity activity, List<Item> items) {
this.host = activity;
this.items = items;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// inflate layout and retrieve binding
ListItemBinding binding = DataBindingUtil.inflate(host.getLayoutInflater(),
R.layout.list_item, parent, false);
return new ItemViewHolder(binding);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Item item = items.get(position);
ItemViewHolder itemViewHolder = (ItemViewHolder)holder;
itemViewHolder.bindItem(item);
}
@Override
public int getItemCount() {
return items.size();
}
private static class ItemViewHolder extends RecyclerView.ViewHolder {
ListItemBinding binding;
ItemViewHolder(ListItemBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
void bindItem(Item item) {
binding.setItem(item);
binding.executePendingBindings();
}
}
}
Cliquez sur auditeur avec liaison
Créer une interface pour clickHandler
public interface ClickHandler {
public void onButtonClick(View v);
}
XML de mise en page
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="handler"
type="com.example.ClickHandler"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="click me"
android:onClick="@{handler.onButtonClick}"/>
</RelativeLayout>
</layout>
Manipuler l'événement dans votre activité
public class MainActivity extends Activity implements ClickHandler {
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
binding.setHandler(this);
}
@Override
public void onButtonClick(View v) {
Toast.makeText(context,"Button clicked",Toast.LENGTH_LONG).show();
}
}
Evénement personnalisé à l'aide de l'expression lambda
Définir l'interface
public interface ClickHandler {
public void onButtonClick(User user);
}
Créer une classe de modèle
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
XML de mise en page
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="handler"
type="com.example.ClickHandler"/>
<variable
name="user"
type="com.example.User"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}"
android:onClick="@{() -> handler.onButtonClick(user)}"/>
</RelativeLayout>
</layout>
Code d'activité:
public class MainActivity extends Activity implements ClickHandler {
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
binding.setUser(new User("DataBinding User"));
binding.setHandler(this);
}
@Override
public void onButtonClick(User user) {
Toast.makeText(MainActivity.this,"Welcome " + user.getName(),Toast.LENGTH_LONG).show();
}
}
Pour certains écouteurs de vue qui ne sont pas disponibles dans le code xml mais peuvent être définis dans du code java, ils peuvent être associés à une liaison personnalisée.
Classe personnalisée
public class BindingUtil {
@BindingAdapter({"bind:autoAdapter"})
public static void setAdapter(AutoCompleteTextView view, ArrayAdapter<String> pArrayAdapter) {
view.setAdapter(pArrayAdapter);
}
@BindingAdapter({"bind:onKeyListener"})
public static void setOnKeyListener(AutoCompleteTextView view , View.OnKeyListener pOnKeyListener)
{
view.setOnKeyListener(pOnKeyListener);
}
}
Classe de gestionnaire
public class Handler extends BaseObservable {
private ArrayAdapter<String> roleAdapter;
public ArrayAdapter<String> getRoleAdapter() {
return roleAdapter;
}
public void setRoleAdapter(ArrayAdapter<String> pRoleAdapter) {
roleAdapter = pRoleAdapter;
}
}
XML
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/tools" >
<data>
<variable
name="handler"
type="com.example.Handler" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<AutoCompleteTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
bind:autoAdapter="@{handler.roleAdapter}" />
</LinearLayout>
</layout>
Valeur par défaut dans la liaison de données
Le volet Aperçu affiche les valeurs par défaut des expressions de liaison de données si elles sont fournies.
Par exemple :
android:layout_height="@{@dimen/main_layout_height, default=wrap_content}"
Il faudra wrap_content
lors de la conception et agira comme un wrap_content
dans le volet de prévisualisation.
Un autre exemple est
android:text="@{user.name, default=`Preview Text`}"
Il affichera le Preview Text
d'aperçu dans le volet d'aperçu, mais lorsque vous l'exécuterez dans le périphérique / émulateur, le texte réel qui lui est lié sera affiché.
DataBinding avec des variables personnalisées (int, booléen)
Parfois, nous devons effectuer des opérations de base telles que masquer / afficher la vue en fonction d'une valeur unique, pour cette variable unique, nous ne pouvons pas créer de modèle ou ce n'est pas une bonne pratique de créer un modèle pour cela. DataBinding prend en charge les types de données de base pour effectuer ces opérations.
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View" />
<variable
name="selected"
type="Boolean" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World"
android:visibility="@{selected ? View.VISIBLE : View.GONE}" />
</RelativeLayout>
</layout>
et définir sa valeur de classe java.
binding.setSelected(true);
Liaison de données dans un dialogue
public void doSomething() {
DialogTestBinding binding = DataBindingUtil
.inflate(LayoutInflater.from(context), R.layout.dialog_test, null, false);
Dialog dialog = new Dialog(context);
dialog.setContentView(binding.getRoot());
dialog.show();
}
Passer le widget comme référence dans BindingAdapter
XML de mise en page
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="100dp"
app:imageUrl="@{url}"
app:progressbar="@{progressBar}"/>
</LinearLayout>
</layout>
Méthode BindingAdapter
@BindingAdapter({"imageUrl","progressbar"})
public static void loadImage(ImageView view, String imageUrl, ProgressBar progressBar){
Glide.with(view.getContext()).load(imageUrl)
.listener(new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
progressBar.setVisibility(View.GONE);
return false;
}
}).into(view);
}