Используя одностороннюю привязку данных, вы можете установить значение атрибута и настроить прослушиватель, который реагирует на изменение этого атрибута:
<CheckBox android:id="@+id/rememberMeCheckBox" android:checked="@{viewmodel.rememberMe}" android:onCheckedChanged="@{viewmodel.rememberMeChanged}" />
Двусторонняя привязка данных упрощает этот процесс:
<CheckBox android:id="@+id/rememberMeCheckBox" android:checked="@={viewmodel.rememberMe}" />
Нотация @={}
, которая, что немаловажно, включает знак "=", позволяет получать изменения данных свойства и одновременно прослушивать обновления пользователя.
Чтобы реагировать на изменения в резервных данных, вы можете сделать переменную макета реализацией Observable
, обычно BaseObservable
, и использовать аннотацию @Bindable
, как показано в следующем фрагменте кода:
Котлин
class LoginViewModel : BaseObservable { // val data = ... @Bindable fun getRememberMe(): Boolean { return data.rememberMe } fun setRememberMe(value: Boolean) { // Avoids infinite loops. if (data.rememberMe != value) { data.rememberMe = value // React to the change. saveData() // Notify observers of a new value. notifyPropertyChanged(BR.remember_me) } } }
Ява
public class LoginViewModel extends BaseObservable { // private Model data = ... @Bindable public Boolean getRememberMe() { return data.rememberMe; } public void setRememberMe(Boolean value) { // Avoids infinite loops. if (data.rememberMe != value) { data.rememberMe = value; // React to the change. saveData(); // Notify observers of a new value. notifyPropertyChanged(BR.remember_me); } } }
Поскольку метод получения привязываемого свойства называется getRememberMe()
, соответствующий метод установки свойства автоматически использует имя setRememberMe()
.
Дополнительные сведения об использовании BaseObservable
и @Bindable
см. в разделе Работа с наблюдаемыми объектами данных .
Двусторонняя привязка данных с использованием пользовательских атрибутов
Платформа предоставляет реализации двусторонней привязки данных для наиболее распространенных двусторонних атрибутов и прослушивателей изменений, которые вы можете использовать как часть своего приложения. Если вы хотите использовать двустороннюю привязку данных с настраиваемыми атрибутами, вам необходимо работать с аннотациями @InverseBindingAdapter
и @InverseBindingMethod
.
Например, если вы хотите включить двустороннюю привязку данных для атрибута "time"
в пользовательском представлении под названием MyView
, выполните следующие шаги:
Аннотируйте метод, который устанавливает начальное значение и обновляет его при изменении значения, используя
@BindingAdapter
:Котлин
@BindingAdapter("time") @JvmStatic fun setTime(view: MyView, newValue: Time) { // Important to break potential infinite loops. if (view.time != newValue) { view.time = newValue } }
Ява
@BindingAdapter("time") public static void setTime(MyView view, Time newValue) { // Important to break potential infinite loops. if (view.time != newValue) { view.time = newValue; } }
Аннотируйте метод, который считывает значение из представления, используя
@InverseBindingAdapter
:Котлин
@InverseBindingAdapter("time") @JvmStatic fun getTime(view: MyView) : Time { return view.getTime() }
Ява
@InverseBindingAdapter("time") public static Time getTime(MyView view) { return view.getTime(); }
На этом этапе привязка данных знает, что делать, когда данные изменяются (она вызывает метод, аннотированный @BindingAdapter
) и что вызывать, когда изменяется атрибут представления (она вызывает InverseBindingListener
). Однако он не знает, когда и как изменится атрибут.
Для этого вам нужно настроить прослушиватель для представления. Это может быть пользовательский прослушиватель, связанный с вашим пользовательским представлением, или это может быть общее событие, например потеря фокуса или изменение текста. Добавьте аннотацию @BindingAdapter
к методу, который устанавливает прослушиватель изменений свойства:
Котлин
@BindingAdapter("app:timeAttrChanged") @JvmStatic fun setListeners( view: MyView, attrChange: InverseBindingListener ) { // Set a listener for click, focus, touch, etc. }
Ява
@BindingAdapter("app:timeAttrChanged") public static void setListeners( MyView view, final InverseBindingListener attrChange) { // Set a listener for click, focus, touch, etc. }
Прослушиватель включает InverseBindingListener
в качестве параметра. Вы используете InverseBindingListener
, чтобы сообщить системе привязки данных, что атрибут изменился. Затем система может начать вызывать метод, аннотированный с помощью @InverseBindingAdapter
, и так далее.
На практике этот прослушиватель включает в себя некоторую нетривиальную логику, включая прослушиватели для односторонней привязки данных. Пример см. в адаптере для изменения текстового атрибута TextViewBindingAdapter
.
Конвертеры
Если переменную, привязанную к объекту View
, необходимо отформатировать, перевести или каким-либо образом изменить перед отображением, можно использовать объект Converter
.
Например, возьмем объект EditText
, отображающий дату:
<EditText
android:id="@+id/birth_date"
android:text="@={Converter.dateToString(viewmodel.birthDate)}"
/>
Атрибут viewmodel.birthDate
содержит значение типа Long
, поэтому его необходимо отформатировать с помощью конвертера.
Поскольку используется двустороннее выражение, также необходим обратный преобразователь , который позволит библиотеке знать, как преобразовать предоставленную пользователем строку обратно в резервный тип данных, в данном случае Long
. Этот процесс выполняется путем добавления аннотации @InverseMethod
к одному из преобразователей, и эта аннотация ссылается на обратный преобразователь. Пример этой конфигурации показан в следующем фрагменте кода:
Котлин
object Converter { @InverseMethod("stringToDate") @JvmStatic fun dateToString( view: EditText, oldValue: Long, value: Long ): String { // Converts long to String. } @JvmStatic fun stringToDate( view: EditText, oldValue: String, value: String ): Long { // Converts String to long. } }
Ява
public class Converter { @InverseMethod("stringToDate") public static String dateToString(EditText view, long oldValue, long value) { // Converts long to String. } public static long stringToDate(EditText view, String oldValue, String value) { // Converts String to long. } }
Бесконечные циклы с использованием двусторонней привязки данных
Будьте осторожны, чтобы не создавать бесконечные циклы при использовании двусторонней привязки данных. Когда пользователь изменяет атрибут, вызывается метод, аннотированный с помощью @InverseBindingAdapter
, и значение присваивается резервному свойству. Это, в свою очередь, вызовет метод, аннотированный с помощью @BindingAdapter
, что вызовет еще один вызов метода, аннотированного с помощью @InverseBindingAdapter
, и так далее.
По этой причине важно разорвать возможные бесконечные циклы, сравнивая новые и старые значения в методах, аннотированных с помощью @BindingAdapter
.
Двусторонние атрибуты
Платформа предоставляет встроенную поддержку двусторонней привязки данных при использовании атрибутов в следующей таблице. Подробности о том, как платформа обеспечивает такую поддержку, см. в реализациях соответствующих адаптеров привязки:
Сорт | Атрибут(ы) | Привязка адаптера |
---|---|---|
AdapterView | android:selectedItemPosition android:selection | AdapterViewBindingAdapter |
CalendarView | android:date | CalendarViewBindingAdapter |
CompoundButton | android:checked | CompoundButtonBindingAdapter |
DatePicker | android:year android:month android:day | DatePickerBindingAdapter |
NumberPicker | android:value | NumberPickerBindingAdapter |
RadioButton | android:checkedButton | RadioGroupBindingAdapter |
RatingBar | android:rating | RatingBarBindingAdapter |
SeekBar | android:progress | SeekBarBindingAdapter |
TabHost | android:currentTab | TabHostBindingAdapter |
TextView | android:text | TextViewBindingAdapter |
TimePicker | android:hour android:minute | TimePickerBindingAdapter |
Дополнительные ресурсы
Чтобы узнать больше о привязке данных, обратитесь к следующим дополнительным ресурсам.
Образцы
Кодлабы
Сообщения в блоге
Рекомендуется для вас
- Примечание. Текст ссылки отображается, когда JavaScript отключен.
- Работа с наблюдаемыми объектами данных
- Макеты и выражения привязки
- Привязка видов компоновки к компонентам архитектуры