이벤트 처리
데이터 바인딩을 사용하면 뷰에서 전달되는 이벤트를 처리하는 표현식을 작성할 수 있다. 이벤트 속성의 이름은 몇 가지 예외를 빼면 리스너 메서드의 이름을 따른다. 예를 들어 View.OnClickListener
의 onClick()
에 대한 속성의 이름은 android:onClick
이다.
데이터 바인딩으로 이벤트를 처리할 때는 다음 두 가지 메커니즘을 사용한다.
메서드 참조
바인딩 표현식에서 이벤트 발생 시 호출될 리스너 메서드를 참조한다. ::
연산자를 사용하여 참조할 메서드 이름을 지정한다.
이 표현식은 컴파일 타임에 처리되므로 해당하는 메서드가 없거나 서명을 잘못 사용하는 경우 컴파일 에러가 발생한다.
예를 들어 버튼을 눌렀을 때 MyHandler
클래스의 onButtonClick()
을 호출하고자 한다면 다음과 같이 표현식을 사용할 수 있다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="handler"
type="com.example.MyHandler" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout>
...
<Button
...
android:onClick="@{handler::onButtonClick}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
리스너 바인딩
바인딩 표현식에 기존 메서드를 참조하는 것이 아니라 이벤트 발생 시 실행할 람다 함수를 작성한다. 표현식에서 콜백을 사용하면 필요한 리스너가 자동으로 생성되어 이벤트에 등록된다. 그리고 이벤트가 발생하면 해당 표현식이 처리된다. 이벤트의 반환 타입이 void
가 아니라면 표현식도 해당 타입을 반환해야 한다.
예를 들어 다음처럼 Presenter
클래스의 onSaveClick(Task)
에 클릭 이벤트를 바인딩할 수 있다.
class Presenter {
fun onSaveClick(task: Task) { ... }
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="task"
type="com.android.example.Task" />
<variable
name="presenter"
type="com.android.example.Presenter" />
</data>
<LinearLayout ... >
<Button
...
android:onClick="@{() -> presenter.onSaveClick(task)}" />
</LinearLayout>
</layout>
관찰 가능한 데이터
데이터가 관찰 가능하다(observable)는 것은 다른 객체에서 해당 데이터의 변경 사항을 알 수 있다는 것이다.
일반 데이터 타입을 사용하면 데이터가 변경되어도 UI가 자동으로 갱신되지 않지만 관찰 가능한 객체를 사용하면 그렇게 만들 수 있다.
Observable 필드
ObservableField
를 사용하면 필드를 관찰 가능하게 할 수 있다.
원시(primitive) 타입의 경우 다음 클래스를 사용할 수도 있다.
ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable
class User {
val firstName = ObservableField<String>()
val lastName = ObservableField<String>()
val age = ObservableInt()
}
Observable 컬렉션
다음 클래스를 사용하면 관찰해야 하는 데이터를 컬렉션으로 모으고 키를 통해 액세스하여 사용할 수 있다.
ObservableArrayMap
키가String
같은 참조형 타입일 경우 유용하다.
ObservableArrayMap<String, Any>().apply { put("firstName", "Google") put("lastName", "Inc.") put("age", 17) }
<data> <import type="android.databinding.ObservableMap"/> <variable name="user" type="ObservableMap<String, Object>"/> </data> <TextView android:text="@{user.lastName}" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:text="@{String.valueOf(1 + (Integer)user.age)}" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
ObservableArrayList
키가 정수 타입일 경우 유용하다.
ObservableArrayList<Any>().apply { add("Google") add("Inc.") add(17) }
<data> <import type="android.databinding.ObservableList"/> <import type="com.example.my.app.Fields"/> <variable name="user" type="ObservableList<Object>"/> </data> <TextView android:text='@{user[Fields.LAST_NAME]}' android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}' android:layout_width="wrap_content" android:layout_height="wrap_content"/>
Observable 객체
Observable
인터페이스를 구현하면 관찰 가능한 객체의 프로퍼티가 변경되면 실행되는 리스너를 등록할 수 있다. 데이터 바인딩 라이브러리는 리스너 등록 메커니즘이 구현된 BaseObservable
클래스를 제공한다. BaseObservable
을 구현하는 데이터 클래스는 게터에 Bindable
어노테이션을 추가하고 세터에서 notifyPropertyChanged()
를 호출하여 프로퍼티에 대한 변경 사항을 알려야 한다.
class User : BaseObservable() {
@get:Bindable
var firstName: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.firstName)
}
@get:Bindable
var lastName: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.lastName)
}
}
데이터 바인딩은 데이터 바인딩에 사용된 리소스의 ID를 포함하는 BR
클래스를 모듈 패키지 안에 생성한다. Bindable
어노테이션은 컴파일 도중에 BR
클래스 안에 항목을 생성한다. 데이터 클래스의 상위 클래스를 변경할 수 없으면 PropertyChangeRegistry
객체로 Observable
인터페이스를 구현하여 효율적으로 리스너를 등록하고 알릴 수 있다.
'Android' 카테고리의 다른 글
데이터 바인딩 (4) : 양방향 바인딩 (0) | 2022.11.05 |
---|---|
데이터 바인딩 (3) : 바인딩 어댑터 (0) | 2022.11.03 |
데이터 바인딩 (1) : 기본 사용법 (0) | 2022.10.29 |
컨텐츠 프로바이더 (0) | 2022.09.19 |
JobScheduler로 백그라운드 작업 예약하기 (0) | 2022.09.05 |