Android
Biblioteka wiązania danych
Szukaj…
Uwagi
Ustawiać
Przed użyciem powiązania danych musisz włączyć wtyczkę w swoim build.gradle
.
android {
....
dataBinding {
enabled = true
}
}
Uwaga: Powiązanie danych zostało dodane do wtyczki Android Gradle w wersji 1.5.0
Wiążące nazwy klas
Wtyczka powiązania danych generuje nazwę klasy powiązania, konwertując nazwę pliku układu na wielkość liter Pascala i dodając „Binding” na końcu. Zatem item_detail_activity.xml
wygeneruje klasę o nazwie ItemDetailActivityBinding
.
Zasoby
Podstawowe wiązanie pól tekstowych
Konfiguracja Gradle (moduł: aplikacja)
android {
....
dataBinding {
enabled = true
}
}
Model danych
public class Item {
public String name;
public String description;
public Item(String name, String description) {
this.name = name;
this.description = description;
}
}
Układ XML
Pierwszym krokiem jest zawinięcie układu w znacznik <layout>
, dodanie elementu <data>
i dodanie elementu <variable>
do modelu danych.
Następnie możesz powiązać atrybuty XML z polami w modelu danych za pomocą @{model.fieldname}
, gdzie model
to nazwa zmiennej, a nazwa fieldname
to pole, do którego chcesz uzyskać dostęp.
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>
Dla każdego pliku układu XML poprawnie skonfigurowanego z powiązaniami wtyczka Android Gradle generuje odpowiednią klasę: powiązania. Ponieważ mamy układ o nazwie item_detail_activity , odpowiednia wygenerowana klasa wiązania nazywa się ItemDetailActivityBinding
.
Wiązanie to można następnie wykorzystać w działaniu takim jak:
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);
}
}
Wiązanie metodą akcesorium
Jeśli twój model ma prywatne metody, biblioteka wiązania danych nadal umożliwia dostęp do nich w twoim widoku bez używania pełnej nazwy metody.
Model danych
public class Item {
private String name;
public String getName() {
return name;
}
}
Układ 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>
Odwoływanie się do klas
Model danych
public class Item {
private String name;
public String getName() {
return name;
}
}
Układ XML
Musisz zaimportować klasy, do których istnieją odniesienia, tak jak w Javie.
<?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>
Uwaga: Pakiet java.lang.*
Jest importowany automatycznie przez system. (To samo robi JVM
dla Java
)
Wiązanie danych we fragmencie
Model danych
public class Item {
private String name;
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
}
Układ 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>
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();
}
Wbudowane dwukierunkowe wiązanie danych
Dwukierunkowe wiązanie danych obsługuje następujące atrybuty:
Element | Nieruchomości |
---|---|
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 |
Stosowanie
<layout ...>
<data>
<variable type="com.example.myapp.User" name="user"/>
</data>
<RelativeLayout ...>
<EditText android:text="@={user.firstName}" .../>
</RelativeLayout>
</layout>
Zauważ, że wyrażenie Binding @={}
ma dodatkowe =
, które jest niezbędne do dwukierunkowego Binding . Nie można używać metod w dwukierunkowych wyrażeniach wiążących.
Powiązanie danych w adapterze RecyclerView
Możliwe jest również użycie powiązania danych w ramach adaptera RecyclerView
.
Model danych
public class Item {
private String name;
public String getName() {
return name;
}
}
Układ XML
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>
Klasa adaptera
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();
}
}
}
Kliknij nasłuchiwanie z wiązaniem
Utwórz interfejs dla ClickHandler
public interface ClickHandler {
public void onButtonClick(View v);
}
Układ 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>
Obsługuj wydarzenie w swojej działalności
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();
}
}
Zdarzenie niestandardowe przy użyciu wyrażenia lambda
Zdefiniuj interfejs
public interface ClickHandler {
public void onButtonClick(User user);
}
Utwórz klasę modelu
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;
}
}
Układ 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>
Kod działania:
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();
}
}
W przypadku niektórych programów nasłuchujących widoku, które nie są dostępne w kodzie XML, ale można je ustawić w kodzie Java, można je powiązać z niestandardowym wiązaniem.
Klasa niestandardowa
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);
}
}
Klasa obsługi
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>
Wartość domyślna w powiązaniu danych
Okienko podglądu wyświetla wartości domyślne dla wyrażeń powiązania danych, jeśli są podane.
Na przykład :
android:layout_height="@{@dimen/main_layout_height, default=wrap_content}"
Podczas projektowania zajmie wrap_content
i będzie działał jako wrap_content
w okienku podglądu.
Innym przykładem jest
android:text="@{user.name, default=`Preview Text`}"
Wyświetli Preview Text
w okienku podglądu, ale po uruchomieniu go w urządzeniu / emulatorze zostanie wyświetlony powiązany z nim tekst
Wiązanie danych ze zmiennymi niestandardowymi (int, boolean)
Czasami musimy wykonać podstawowe operacje, takie jak ukrywanie / pokazywanie widoku w oparciu o jedną wartość, dla tej jednej zmiennej nie możemy stworzyć modelu lub nie jest dobrą praktyką tworzenie modelu dla tego. DataBinding obsługuje podstawowe typy danych do wykonywania tych operacji.
<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>
i ustaw jego wartość z klasy java.
binding.setSelected(true);
Wiązanie danych w oknie dialogowym
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();
}
Przekaż widget jako odniesienie w BindingAdapter
Układ 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>
Metoda 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);
}