Используя одностороннюю привязку данных, вы можете установить значение атрибута и настроить прослушиватель, который реагирует на изменение этого атрибута:
<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
:
На этом этапе привязка данных знает, что делать, когда данные изменяются (она вызывает метод, аннотированный @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 |
Дополнительные ресурсы
Чтобы узнать больше о привязке данных, обратитесь к следующим дополнительным ресурсам.
Образцы
Кодлабы
Сообщения в блоге
Пока рекомендаций нет.
Попытайтесь войти в свой аккаунт Google.