양방향 데이터 결합

단방향 데이터 결합을 사용하면 속성에 값을 설정하고 이 속성의 변경에 반응하는 리스너를 설정할 수 있습니다.

<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 주석을 사용하면 됩니다.

Kotlin

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)
        }
    }
}

Java

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);
        }
    }
}

결합 가능한 속성의 getter 메서드는 getRememberMe()라고 하므로 속성의 상응하는 setter 메서드는 자동으로 setRememberMe() 이름을 사용합니다.

BaseObservable@Bindable 사용에 관한 자세한 내용은 식별 가능한 데이터 객체 작업을 참고하세요.

맞춤 속성을 사용한 양방향 데이터 결합

플랫폼은 앱의 일부로 사용할 수 있는 가장 일반적인 양방향 속성과 변경 리스너의 양방향 데이터 결합 구현을 제공합니다. 맞춤 속성이 있는 양방향 데이터 결합을 사용하려면 @InverseBindingAdapter@InverseBindingMethod 주석을 사용해야 합니다.

예를 들어 MyView라는 맞춤 뷰에서 "time" 속성에 양방향 데이터 결합을 사용 설정하려면 다음 단계를 완료하세요.

  1. 초깃값을 설정하고 값이 변경될 때 업데이트하는 메서드에 @BindingAdapter를 사용하여 주석을 추가합니다.

    Kotlin

    @BindingAdapter("time")
    @JvmStatic fun setTime(view: MyView, newValue: Time) {
        // Important to break potential infinite loops.
        if (view.time != newValue) {
            view.time = newValue
        }
    }

    Java

    @BindingAdapter("time")
    public static void setTime(MyView view, Time newValue) {
        // Important to break potential infinite loops.
        if (view.time != newValue) {
            view.time = newValue;
        }
    }
  2. 뷰에서 값을 읽는 메서드에 @InverseBindingAdapter를 사용하여 주석을 추가합니다.

    Kotlin

    @InverseBindingAdapter("time")
    @JvmStatic fun getTime(view: MyView) : Time {
        return view.getTime()
    }

    Java

    @InverseBindingAdapter("time")
    public static Time getTime(MyView view) {
        return view.getTime();
    }

이 시점에서 데이터 결합은 데이터가 변경될 때 실행할 작업 (@BindingAdapter 주석이 달린 메서드 호출)과 뷰 속성이 변경될 때 호출할 작업 (InverseBindingListener 호출)을 알고 있습니다. 그러나 속성이 언제 어떻게 변경되는지는 알지 못합니다.

속성의 변경 시기 또는 방식을 알기 위해서는 뷰에 리스너를 설정해야 합니다. 이는 맞춤 뷰와 연결된 맞춤 리스너이거나 포커스 상실 또는 텍스트 변경과 같은 일반 이벤트일 수 있습니다. 속성 변경의 리스너를 설정하는 메서드에 @BindingAdapter 주석을 추가합니다.

Kotlin

@BindingAdapter("app:timeAttrChanged")
@JvmStatic fun setListeners(
        view: MyView,
        attrChange: InverseBindingListener
) {
    // Set a listener for click, focus, touch, etc.
}

Java

@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 주석을 추가하고 이 주석이 역변환기를 참조하도록 하면 완료됩니다. 다음 코드 스니펫은 이 구성의 예를 보여줍니다.

Kotlin

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.
    }
}

Java

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

추가 리소스

데이터 결합에 관한 자세한 내용은 다음 추가 리소스를 참고하세요.

샘플

Codelab

블로그 게시물