안드로이드 DataBinding (데이터 바인딩)
23 Jul 2019 | android programming thread handler데이터 바인딩이란?
Part of Android Jetpack
https://developer.android.com/topic/libraries/data-binding 를 참고하여 작성하였습니다.
아래의 코드는 안드로이드 UI 프로그래밍시 많이 보는 코드이다.
findViewById<TextView>(R.id.sample_text).apply {
text = viewModel.userName
}
데이터 바인딩을 사용하면 위의 자바 코드를 부르는것을 생략 가능하다.
<TextView
android:text="@{viewmodel.userName}" />
데이터 바인딩 사용하기
환경설정
build.gradle에 dataBinding enabled로 설정하기
android {
...
dataBinding {
enabled = true
}
}
레이아웃 파일
데이터 바인딩 레이아웃 파일은 일반 레이아웃 파일과 약간 다르다. root 태그를 layout으로 감싸고 그 다음 data와 view 엘리먼트가 따른다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</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="@{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
</layout>
데이터 바인딩하기
각각의 레이아웃 파일마다 바인딩 클래스가 만들어진다. 기본적으로 클래스의 이름은 레이아웃 파일의 이름에 따른다. 만약 activity_main.xml 이었다면 ActivityMainBinding 이라는 이름으로 생기게 된다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(
this, R.layout.activity_main)
binding.user = User("Test", "User")
}
Collection Data 바인딩하기
<data>
<import type="android.util.SparseArray"/>
<import type="java.util.Map"/>
<import type="java.util.List"/>
<variable name="list" type="List<String>"/>
<variable name="sparse" type="SparseArray<String>"/>
<variable name="map" type="Map<String, String>"/>
<variable name="index" type="int"/>
<variable name="key" type="String"/>
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"
바인딩 어댑터
바인딩시 몇 속성들은 setter를 가지고 있지 않을 수 있다. 이런 상황에는 BindingMethods 어노테이션을 사용한다. 이 어노테이션은 클래스에 쓰인다.
아래 예시에서는 android:tint 라는 attribute가 setImageTintList라는 메소드와 연관되어 있다. 대부분의 경우에는 안드로이드 프레임워크 클래스들의 세터를 다시 세팅할 필요는 없다.
@BindingMethods(value = [
BindingMethod(
type = android.widget.ImageView::class,
attribute = "android:tint",
method = "setImageTintList")])
양방향 데이터 바인딩
단방향 데이터 바인딩을 사용하면, 아래와 같이 변경에 반응하는 리스너와 값을 세팅할 수 있다.
<CheckBox
android:id="@+id/rememberMeCheckBox"
android:checked="@{viewmodel.rememberMe}"
android:onCheckedChanged="@{viewmodel.rememberMeChanged}"
/>
양방향 바인딩은 위의 코드를 아래처럼 줄여 준다. @={} 을 사용하여 데이터 변경과 프로퍼티의 변경을 받고 유저의 업데이트를 동시에 받을 수 있다.
<CheckBox
android:id="@+id/rememberMeCheckBox"
android:checked="@={viewmodel.rememberMe}"
/>
Observable
데이터의 수정이 일어났을 때 그것을 감지할수 있게 하는 것이다.
observable 클래스에는 세가지 타입이 있는데, object, fields, collectios이다.
이중 하나의 observable 데이터에 변화가 생기면 UI가 자동으로 업데이트된다.
뒤에서 변하는 변화를 감지하기 위해서 레이아웃 변수에 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)
}
}
}