binding 글 링크
개념-데이터-바인딩data-Binding (1)
개념-데이터-바인딩data-Binding (2)
개념-데이터-바인딩data-Binding (3)
개념-데이터-바인딩data-Binding (4)
개념-데이터-바인딩data-Binding (5)
1. Work with observable data objects
databinding 에서 임의의 데이터 객체를 사용하여 레이아웃과 바인딩을 구현 할 수 있지만 바인딩 하고 있는 객체의 값이 변경 되어도 UI는 업데이트 가 안됩니다. 데이터가 변경 되었을 때 이를 알려주는 기능을 데이터 객체에 부여하면 databinding 의 장점을 극대화 시킬 수 있습니다. databinding 은 데이터 변경에 대응하기 위한 세 가지 유형 Observable objects, Observable fields, Observable collections이 있습니다.
2. Observable Objects
바인딩 하려는 객체에 androidx.databinding 패키지의 Observable 인터페이스를 구현하면 해당 객체에 단일 리스너를 연결하여 그 객체에 모든 속성의 변경사항을 수신 할 수 있게 됩니다. 편의를 위해 BaseObservable 클래스를 제공하고 있으며, 원하는 객체에 BaseObservable 클래스를 확장하여 사용 할 수 있습니다.
내부적으로 리스너를 추가/해제 하는 메커니즘을 갖고 있지만 최종적으로 데이터 변경에 대해 처리를 하기 위해서는 해당 필드의 접근자 메소드에 androidx.databinding 패키지의 Bindable annotation 을 추가하고 설정자 메서드에서 이를 알림으로써 구현 할 수 있습니다. 예제코드를 살펴보겠습니다.
data class User(private var firstName: String,
private var lastName: String) : BaseObservable() {
//데이터 변경 시 알림을 수신 하고자 하는 필드에 Bindable annotation 추가
@Bindable
fun getFirstName() = firstName
@Bindable
fun getLastName() = lastName
fun setFirstName(firstName: String) {
this.firstName = firstName
//데이터 변경을 알리기 위해 notifyPropertyChanged() 호출
notifyPropertyChanged(BR.firstName)
}
fun setLastName(lastName: String) {
this.lastName = lastName
notifyPropertyChanged(BR.lastName)
}
}
getFirstName() , getLastName() 에 Bindable annotation 을 설정 하였습니다. Bindable annotation 을 설정한 필드는 컴파일 시 BR 이라는 클래스에 filedId 를 자동 생성하게 되는데, 이후 데이터 변경 알림을 위해 notifyPropertyChanged(filedId : Int) 를 호출 할 때 파라미터로 사용 됩니다. (BR 클래스 파일은 모듈 패키지 내에 생성 됩니다) 그리고 setFirstName() , setLastName() 내에서 notifyPropertyChanged() 를 호출하여 값이 변경 되었음을 알리게 됩니다.
위 예제코드에서는 data class 로 작성하였는데 만약 일반 class 로 작성한다면 아래와 같은 방법으로도 사용 할 수 있습니다. 참고하시기 바랍니다.
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)
}
}
3. Observable Objects 구현 예제 코드
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="activity"
type="com.project.databindingobservable.MainActivity" />
<variable
name="user"
type="com.project.databindingobservable.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:textSize="50sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
tools:text="firstName"/>
<TextView
android:textSize="50sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{user.lastName}"
tools:text="lastName"/>
</LinearLayout>
</layout>
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
binding.activity = this@MainActivity
setObservable()
}
fun setObservable() {
var user : User = User()
binding.user = user
user.firstName = "Test"
user.lastName = "User"
Handler().postDelayed(Runnable {
run {
user.firstName = "Test modify"
user.lastName = "User modify"
}
},5000)
}
}
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)
}
}
4. Observable Fields
위에서 데이터 객체에 Observable interface 를 구현하여 사용하는 방식을 알아보았습니다. 다음으로 Databinding library 에서는 각 필드단위로 Observable를 구현 할 수 있는 Observable Fileds를 제공 합니다. 제공하는 Observable Fileds 목록은 아래와 같습니다.
ObservableField
ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable
예제 코드를 보겠습니다.
class User {
val firstName: ObservableField<String> = ObservableField()
val lastName: ObservableField<String> = ObservableField()
val age: ObservableInt = ObservableInt()
}
이렇게 Observable 을 구현하려는 필드에 위와 같이 선언 해서 사용 할 수 있습니다. ObservableField는 박싱/언박싱 방지를 위해 final(kotlin은 val)로 선언해야 합니다.
ObservableField 속성 Access 방법으로 (기존 setter/getter가 아닌 set() / get()접근자 메서드 사용) : 기존 Setter/Getter 메서드가 아닌 set() / get() 접근자 메서드를 사용합니다
ObservableField 타입의 속성이여서 값 변경시 자동으로 View에 알림(notiy)를 줘서 UI업데이트가 가능합니다. Observable 인터페이스를 구현한 Observable Object와 달리 사용자가 notify 메서드 호출 할 필요가 없습니다.
코틀린
user.firstName = "Google"
val age = user.age
자바
user.firstName.set("Google");
int age = user.age.get();
5. Observable Collection
마지막으로 databinding library 는 Observable Collection 을 제공 합니다. 제공하는 Collection 은 아래와 같습니다.
ObservableArrayList
ObservableArrayMap<K,V>
ObservableMap<K,V>
ObservableArrayMap 을 사용해보겠습니다. 키가 String 과 같은 참조 형식 일때 사용하기 적절합니다
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.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"/>
ObservableList 의 예제도 한번 살펴 보겠습니다. List 에 값을 저장하고 바인딩 식에서 index 를 통해 바인딩이 가능합니다.
<data>
<import type="android.databinding.ObservableList"/>
<variable name="user" type="ObservableList<Object>"/>
</data>
....
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user[0]}" />
<TextView
android:id="@+id/test1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user[1]}" />
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.user = ObservableArrayList<Any>().apply{
add("Google")
add("Inc.")
add(17)
}
kotlin 에서는 Object 대신 Any 라는 이름을 사용하지만 레이아웃에 variable 을 생성할때는 Object 로 선언해야 하는 점을 주의 하시기 바랍니다.
https://developer.android.com/topic/libraries/data-binding/start
https://developer.android.com/topic/libraries/data-binding
https://developer.android.com/topic/libraries/data-binding/expressions
https://developer.android.com/topic/libraries/data-binding/observability