Android
Libreria di associazione dati
Ricerca…
Osservazioni
Impostare
Prima di utilizzare l'associazione dati, è necessario abilitare il plug-in in build.gradle
.
android {
....
dataBinding {
enabled = true
}
}
Nota: il collegamento dati è stato aggiunto al plug-in Android Gradle nella versione 1.5.0
Nomi delle classi vincolanti
Il plug-in di associazione dei dati genera un nome di classe di associazione convertendo il nome del file del layout in caso Pascal e aggiungendo "Binding" alla fine. Quindi item_detail_activity.xml
genererà una classe chiamata ItemDetailActivityBinding
.
risorse
Binding del campo di testo di base
Gradle (Module: app) Configuration
android {
....
dataBinding {
enabled = true
}
}
Modello di dati
public class Item {
public String name;
public String description;
public Item(String name, String description) {
this.name = name;
this.description = description;
}
}
Layout XML
Il primo passo è il wrapping del layout in un tag <layout>
, aggiungendo un elemento <data>
e aggiungendo un elemento <variable>
per il tuo modello dati.
Quindi è possibile associare gli attributi XML ai campi nel modello dati utilizzando @{model.fieldname}
, dove model
è il nome della variabile e fieldname
è il campo a cui si desidera accedere.
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>
Per ogni file di layout XML configurato correttamente con i binding, il plug-in Android Gradle genera una classe corrispondente: binding. Poiché abbiamo un layout denominato item_detail_activity , la corrispondente classe di associazione generata è chiamata ItemDetailActivityBinding
.
Questo legame può quindi essere utilizzato in un'attività come questa:
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);
}
}
Associazione con un metodo di accesso
Se il tuo modello ha metodi privati, la libreria di associazione ti consente comunque di accedervi nella tua vista senza utilizzare il nome completo del metodo.
Modello di dati
public class Item {
private String name;
public String getName() {
return name;
}
}
Layout 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">
<!-- 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>
Classi di riferimento
Modello di dati
public class Item {
private String name;
public String getName() {
return name;
}
}
Layout XML
È necessario importare le classi di riferimento, proprio come faresti in 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>
Nota: il pacchetto java.lang.*
Viene importato automaticamente dal sistema. (Lo stesso è fatto da JVM
per Java
)
Databinding in Fragment
Modello di dati
public class Item {
private String name;
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
}
Layout 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}"/>
</LinearLayout>
</layout>
Frammento
@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();
}
Associazione dati bidirezionale integrata
Il collegamento dati bidirezionale supporta i seguenti attributi:
Elemento | Proprietà |
---|---|
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 |
uso
<layout ...>
<data>
<variable type="com.example.myapp.User" name="user"/>
</data>
<RelativeLayout ...>
<EditText android:text="@={user.firstName}" .../>
</RelativeLayout>
</layout>
Si noti che l'espressione Binding @={}
ha un valore aggiuntivo =
, che è necessario per il Binding a due vie . Non è possibile utilizzare i metodi nelle espressioni Binding bidirezionali.
Associazione dati in Adattatore RecyclerView
È anche possibile utilizzare l'associazione dati all'interno del tuo Adattatore RecyclerView
.
Modello di dati
public class Item {
private String name;
public String getName() {
return name;
}
}
Layout XML
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>
Classe dell'adattatore
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();
}
}
}
Clicca listener con Binding
Crea un'interfaccia per clickHandler
public interface ClickHandler {
public void onButtonClick(View v);
}
Layout XML
<?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>
Gestisci l'evento nella tua attività
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();
}
}
Evento personalizzato usando l'espressione lambda
Definisci interfaccia
public interface ClickHandler {
public void onButtonClick(User user);
}
Crea una classe del modello
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;
}
}
Layout XML
<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>
Codice attività:
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();
}
}
Per alcuni listener di visualizzazione che non sono disponibili nel codice xml ma possono essere impostati in codice java, possono essere associati con l'associazione personalizzata.
Classe personalizzata
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 dell'handler
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>
Valore predefinito in Associazione dati
Il riquadro Anteprima mostra i valori predefiniti per le espressioni di associazione dati, se fornite.
Per esempio :
android:layout_height="@{@dimen/main_layout_height, default=wrap_content}"
wrap_content
progettazione occorrerà wrap_content
e agirà come wrap_content
nel riquadro di anteprima.
Un altro esempio è
android:text="@{user.name, default=`Preview Text`}"
Preview Text
di anteprima nel riquadro di anteprima ma, quando lo si esegue in dispositivo / emulatore, verrà visualizzato il testo effettivo associato ad esso
DataBinding con variabili personalizzate (int, booleano)
A volte abbiamo bisogno di eseguire operazioni di base come nascondere / mostrare la vista in base al singolo valore, per quella singola variabile non possiamo creare il modello o non è una buona pratica creare un modello per quello. DataBinding supporta i tipi di dati di base per eseguire tali oprazioni.
<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>
e imposta il suo valore dalla classe java.
binding.setSelected(true);
Databinding in Dialog
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();
}
Passa il widget come riferimento in BindingAdapter
Layout XML
<?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>
Metodo 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);
}