Android
Библиотека привязки данных
Поиск…
замечания
Настроить
Прежде чем использовать привязку данных, вы должны включить плагин в build.gradle
.
android {
....
dataBinding {
enabled = true
}
}
Примечание: привязка данных была добавлена в плагин Android Gradle версии 1.5.0
Названия классов привязки
Плагин привязки данных генерирует имя класса привязки путем преобразования имени файла макета в файл Pascal и добавления «Связывание» до конца. Таким образом item_detail_activity.xml
будет генерировать класс с именем ItemDetailActivityBinding
.
Ресурсы
Связывание основного текстового поля
Конфигурация Gradle (Module: app)
android {
....
dataBinding {
enabled = true
}
}
Модель данных
public class Item {
public String name;
public String description;
public Item(String name, String description) {
this.name = name;
this.description = description;
}
}
Макет XML
Первым шагом является перенос вашего макета в <layout>
, добавление элемента <data>
и добавление элемента <variable>
для вашей модели данных.
Затем вы можете привязать атрибуты XML к полям в модели данных, используя @{model.fieldname}
, где model
- это имя переменной, а fieldname
- поле, к которому вы хотите получить доступ.
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>
Для каждого файла макета XML, правильно настроенного с привязками, плагин Android Gradle генерирует соответствующий класс: привязки. Поскольку у нас есть макет с именем item_detail_activity , соответствующий сгенерированный класс привязки называется ItemDetailActivityBinding
.
Затем это связывание можно использовать в Деятельности, например:
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);
}
}
Связывание с методом доступа
Если ваша модель имеет частные методы, библиотека привязки данных по-прежнему позволяет вам получить к ней доступ в вашем представлении без использования полного имени метода.
Модель данных
public class Item {
private String name;
public String getName() {
return name;
}
}
Макет 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>
Ссылки на классы
Модель данных
public class Item {
private String name;
public String getName() {
return name;
}
}
Макет XML
Вы должны импортировать ссылочные классы, как и в 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>
Примечание . Пакет java.lang.*
Автоматически импортируется системой. (То же самое делает JVM
для Java
)
Сопоставление данных в фрагменте
Модель данных
public class Item {
private String name;
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
}
Макет 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>
Фрагмент
@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();
}
Встроенная двусторонняя привязка данных
Двусторонняя привязка данных поддерживает следующие атрибуты:
Элемент | свойства |
---|---|
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 |
использование
<layout ...>
<data>
<variable type="com.example.myapp.User" name="user"/>
</data>
<RelativeLayout ...>
<EditText android:text="@={user.firstName}" .../>
</RelativeLayout>
</layout>
Обратите внимание, что выражение Binding @={}
имеет дополнительный =
, что необходимо для двухстороннего связывания . Невозможно использовать методы в двухсторонних выражениях привязки.
Связывание данных в адаптере RecyclerView
Также возможно использовать привязку данных в вашем адаптере RecyclerView
.
Модель данных
public class Item {
private String name;
public String getName() {
return name;
}
}
XML-макет
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>
Класс адаптера
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();
}
}
}
Нажмите прослушиватель с привязкой
Создать интерфейс для clickHandler
public interface ClickHandler {
public void onButtonClick(View v);
}
Макет 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>
Обработка события в вашей деятельности
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();
}
}
Пользовательское событие с использованием выражения лямбда
Определить интерфейс
public interface ClickHandler {
public void onButtonClick(User user);
}
Создать класс модели
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
<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>
Код мероприятия:
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();
}
}
Для некоторого слушателя, который недоступен в коде xml, но может быть установлен в java-коде, его можно связать с пользовательской привязкой.
Пользовательский класс
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);
}
}
Класс обработчика
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>
Значение по умолчанию в привязке данных
На панели «Предварительный просмотр» отображаются значения по умолчанию для выражений привязки данных, если они предоставлены.
Например :
android:layout_height="@{@dimen/main_layout_height, default=wrap_content}"
Это займет wrap_content
при проектировании и будет действовать как wrap_content
в области предварительного просмотра.
Другим примером является
android:text="@{user.name, default=`Preview Text`}"
Он отобразит Preview Text
в области предварительного просмотра, но когда вы запустите его в устройстве / эмуляторе, будет отображаться фактический текст, привязанный к нему.
DataBinding с пользовательскими переменными (int, boolean)
Иногда нам нужно выполнять основные операции, такие как hide / show view, основанные на одном значении, для этой единственной переменной мы не можем создать модель, или это не очень хорошая практика для создания модели для этого. DataBinding поддерживает базовые типы данных для выполнения этих отпечатков.
<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>
и установить его значение из класса java.
binding.setSelected(true);
Связывание данных в диалоге
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();
}
Пропустить виджет в качестве ссылки в BindingAdapter
Макет 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>
Метод 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);
}