ObservableField (@Android/Databinding)
: 객체를 observable(=관찰 가능)하게 만드는 wrapper 클래스.
- Android의 Databinding의 소속으로 DataBinding을 활성화해야 사용 가능
java.lang.Object | ||
↳ | android.databinding.BaseObservable | |
↳ | android.databinding.ObservableField<T> |
- 사용 : ViewModel에서 로직이 변경 시 UI(의 작은 부분)가 자동 업데이트되도록 하기 위해 사용
- 사용법)
ㄴ> 생성 : 아래와 같은 방법으로 생성가능
1) Observable Primitive타입클래스 ex) Observable<String>(), ObservableInt()
2) Observable Collection타입클래스 ex) ObservableArrayMap<String, Any>()
3) 리스너 등록 메커니즘을 구현하는 BaseObservable를 상속 ex) 아래 별도 기재
ㄴ> 값설정 : get() / set(T value)
public ObservableInt countObservableInt = new ObservableInt(0);
countObservableInt.set(countObservableInt.get() + 1);
ㄴ> 관찰 : Databinding으로 레이아웃 XML파일에서 바로 변화 관찰해 사용가능
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewmodel"
type="com.example.android.observableint.MyViewModel" />
</data>
...
<!-- 여기가 중요!! -->
<TextView
...
andorid:text="@{String.valueOf(viewmodel.countObservableInt)}" />
추가 활용)
BaseObservable
- 사용 : Observable객체의 값이 변경될 때 알림을 받는 리스너를 등록 시 BaseObservable를 상속받는다!
- 속성이 변경될 때 알려준다.
- 사용법
1. 생성 : BaseObservable를 상속받는 Observable데이터클래스 생성
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)
}
}
2. Getter : 주석 '@Bindable'은 모든 getter 위에 써줘야 합니다
∵ Databinding에 사용된 리소스의 ID를 포함하는 모듈 패키지에 이름이 BR인 BR클래스를 생성하는데
@Bindable 주석을 통해 컴파일 시 필드 값이 변경되면 BR 클래스에 필드를 생성하여 반응합니다.
+) BR 클래스 : 처리할 모든 반응 값을 저장하기 위해 데이터 바인딩에 의해 생성되는 클래스
data class ProfileUIModel(
private val _name: String,
private val _age: Int
): BaseObservable() {
var name: String
@Bindable get() = _name
ㄴ> 어노테이션 @Bindable, @get:Bindable
@Bindable : 기본적인 getter위에 붙여주는 어노테이션
@get:Bindable : getter에 @Bindable 을 합쳐버린 형태
// 아래 코드 1,2,3은 모두 동일하다.
// 1. @Bindable get() 버전
@get:Bindable
var userIds: MutableList<Long> = mutableListOf()
private set(value) {
field = value
notifyPropertyChanged(BR.userIds)
}
// 2. @Bindable 버전
var userIds: MutableList<Long> = mutableListOf()
@Bindable get() = _userIds
set(value) {
field = value
notifyPropertyChanged(BR.userIds)
}
// 3. 자바버전
private ArrayList<Long> userIds = new ArrayList<>();
@Bindable
public ArrayList<Long> getUserIds() {
return userIds;
}
public void setUserIds(ArrayList<Long> userIds) {
this.userIds = userIds;
notifyPropertyChanged(BR.selected);
}
3. Setter
: setter에서 notifyPropertyChanged(BR.필드명) 메서드를 호출해야 setter 작업이 완료됨
notifyChange() : 이 인스턴스의 모든 속성이 변경되었음을 리스너에게 알립니다.
notifyPropertyChanged(int fieldId) : 특정 속성이 변경되었음을 리스너에게 알립니다.
data class ProfileUIModel(
private val _name: String,
private val _age: Int
): BaseObservable() {
var name: String
@Bindable get() = _name
// setter
set(value) {
_name = value
notifyPropertyChanged(BR.name)
}
4. 레이아웃 XML
: '<variable>'태그로 BaseObservable클래스 변수 선언하고,@{변수.필드값}으로 사용
<?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>
<!-- BaseObservable 클래스 선언 -->
<variable
name="item"
type="com.sample.model.ProfileUIModel"
/>
</data>
...
<!-- BaseObservable 클래스 데이터를 'android:text'에 사용 -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{item.name}"
/>
...
[출처]
https://developer.android.com/topic/libraries/data-binding/observability?hl=en#observable_objects
https://developer.android.com/topic/libraries/data-binding/observability?hl=en#observable_objects
https://developer.android.com/reference/android/databinding/Bindable?hl=en#annotations
https://stackoverflow.com/questions/52394858/when-to-use-android-s-livedata-and-observable-field
https://stackoverflow.com/questions/53910028/what-is-getbindable-in-the-android-data-binding-code
https://altongmon.tistory.com/834