LiveData κ°μ²΄λ₯Ό λ°μ΄ν° λ°μΈλ© μμ€λ‘ μ¬μ©νμ¬ λ°μ΄ν° λ³κ²½μ¬νμ UIμ μλμΌλ‘ μ릴 μ μμ.
Observable νλμ κ°μ Observableμ ꡬννλ κ°μ²΄μ λ¬λ¦¬ LiveData κ°μ²΄λ λ°μ΄ν° λ³κ²½ μ¬νμ ꡬλ νλ Observerμ μλͺ μ£ΌκΈ°λ₯Ό μκ³ μμ.
λ°μΈλ© ν΄λμ€μ ν¨κ» LiveData κ°μ²΄λ₯Ό μ¬μ©νλ €λ©΄ lifecycle ownerλ₯Ό μ§μ νμ¬ LiveData κ°μ²΄μ λ²μλ₯Ό μ μν΄μΌ ν¨.
class ViewModelActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Inflate view and obtain an instance of the binding class.
val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)
// Specify the current activity as the lifecycle owner.
binding.setLifecycleOwner(this)
}
}
ViewModel μ»΄ν¬λνΈλ₯Ό μ¬μ©νμ¬ λ°μ΄ν°λ₯Ό λ μ΄μμμ λ°μΈλ©ν μ μμ.
ViewModel μ»΄ν¬λνΈμμλ LiveData κ°μ²΄λ₯Ό μ¬μ©νμ¬ λ°μ΄ν°λ₯Ό λ³ννκ±°λ μ¬λ¬ λ°μ΄ν° μμ€λ₯Ό λ³ν©νλ κ²μ΄ κ°λ₯.
class ScheduleViewModel : ViewModel() {
val userName: LiveData
init {
val result = Repository.userName
userName = Transformations.map(result) { result -> result.value }
}
}
λ°μ΄ν° λ°μΈλ© λΌμ΄λΈλ¬λ¦¬λ ViewModel μ»΄ν¬λνΈμ μννκ² λμ.
λ°μ΄ν° λ°μΈλ© λΌμ΄λΈλ¬λ¦¬μ ν¨κ» ViewModel κ΅¬μ± μμλ₯Ό μ¬μ©νλ©΄ UI λ‘μ§μ λ μ΄μμ μΈλΆμ μ»΄ν¬λνΈλ‘ μ΄λν μ μμΌλ―λ‘ ν
μ€νΈνκΈ°κ° μ©μ΄ν΄μ§.
λ°μ΄ν° λ°μΈλ© λΌμ΄λΈλ¬λ¦¬λ νμν λ λ·°κ° λ°μ΄ν° μμ€μ λ°μΈλ©λκ±°λ λ°μΈλ© ν΄μ λλλ‘ λ³΄μ₯ν¨.
class ViewModelActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Obtain the ViewModel component.
val userModel: UserModel by viewModels()
// Inflate view and obtain an instance of the binding class.
val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)
// Assign the component to a property in the binding class.
binding.viewmodel = userModel
}
}
<CheckBox
android:id="@+id/rememberMeCheckBox"
android:checked="@{viewmodel.rememberMe}"
android:onCheckedChanged="@{() -> viewmodel.rememberMeChanged()}" />
Observable μΈν°νμ΄μ€λ₯Ό ꡬννλ ViewModel μ»΄ν¬λνΈλ₯Ό μ¬μ©νμ¬ λ°μ΄ν° λ³κ²½ μ¬νμ λ€λ₯Έ μ± μ»΄ν¬λνΈμ μ릴 μ μμ.
Observableμ ꡬννλ ViewModel κ΅¬μ± μμλ₯Ό μ¬μ©νλ©΄ μ±μ λ°μΈλ© μ΄λν°λ₯Ό λ ν¨κ³Όμ μΌλ‘ μ μ΄ν μ μμ.
Observable ViewModel μ»΄ν¬λνΈλ₯Ό ꡬννλ €λ©΄ ViewModel ν΄λμ€λ₯Ό μμνκ³ Observable μΈν°νμ΄μ€λ₯Ό ꡬννλ ν΄λμ€λ₯Ό λ§λ€μ΄μΌ ν¨.
addOnPropertyChangedCallback()
λ° RemoveOnPropertyChangedCallback()
λ©μλλ₯Ό μ¬μ©νμ¬ Observerκ° μλ¦Όμ ꡬλ
νκ±°λ ꡬλ
μ·¨μν λ μ¬μ©μ μ μ λ‘μ§μ μ 곡ν μ μμ.
λν notifyPropertyChanged()
λ©μλμμ μμ±μ΄ λ³κ²½λ λ μ€νλλ μ¬μ©μ μ§μ λ‘μ§μ μ 곡ν μ μμ.
/**
* A ViewModel that is also an Observable,
* to be used with the Data Binding Library.
*/
open class ObservableViewModel : ViewModel(), Observable {
private val callbacks: PropertyChangeRegistry = PropertyChangeRegistry()
override fun addOnPropertyChangedCallback(
callback: Observable.OnPropertyChangedCallback) {
callbacks.add(callback)
}
override fun removeOnPropertyChangedCallback(
callback: Observable.OnPropertyChangedCallback) {
callbacks.remove(callback)
}
/**
* Notifies observers that all properties of this instance have changed.
*/
fun notifyChange() {
callbacks.notifyCallbacks(this, 0, null)
}
/**
* Notifies observers that a specific property has changed. The getter for the
* property that changes must be marked with the @Bindable annotation to
* generate a field in the BR class to be used as the fieldId parameter.
*
* @param fieldId The generated BR id for the Bindable field.
*/
fun notifyPropertyChanged(fieldId: Int) {
callbacks.notifyCallbacks(this, fieldId, null)
}
}
λ¨λ°©ν₯ λ°μ΄ν° λ°μΈλ©μ μ¬μ©ν κ²½μ° μμ±μ κ°μ μ€μ νκ³ ν΄λΉ μμ±μ λ³κ²½μ λ°μνλ 리μ€λλ₯Ό μ€μ ν μ μμ.
<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
μ΄λ
Έν
μ΄μ
μ μ¬μ©.
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)
}
}
}
μ¬μ©μ μ μ μμ±κ³Ό ν¨κ» μλ°©ν₯ λ°μ΄ν° λ°μΈλ©μ μ¬μ©νλ €λ©΄ @InverseBindingAdapter
λ° @InverseBindingMethod
μ΄λ
Έν
μ΄μ
μ μ¬μ©ν΄μΌν¨.
@BindingAdapter
λ₯Ό μ¬μ©νμ¬ μ΄κΈ°κ°μ μ€μ νκ³ κ°μ΄ λ³κ²½λλ©΄ μ
λ°μ΄νΈνλ λ©μλμ μ΄λ
Έν
μ΄μ
μ λ¬μμ€.@BindingAdapter("time")
@JvmStatic fun setTime(view: MyView, newValue: Time) {
// Important to break potential infinite loops.
if (view.time != newValue) {
view.time = newValue
}
}
@InverseBindingAdapter
λ₯Ό μ¬μ©νμ¬ λ·°μμ κ°μ μ½λ λ©μλμ μ΄λ
Έν
μ΄μ
μ λ¬μμ€.@InverseBindingAdapter("time")
@JvmStatic fun getTime(view: MyView) : Time {
return view.getTime()
}
μ¬κΈ°μμ λ°μ΄ν° λ°μΈλ©μ λ°μ΄ν°κ° λ³κ²½λ λ μνν μμ (@BindingAdapter μ΄λ Έν μ΄μ μ΄ λ¬λ¦° λ©μλ)κ³Ό λ·° μμ±μ΄ λ³κ²½λ λ νΈμΆν μμ (@InverseBindingListener νΈμΆ)μ μκ³ μμ§λ§,
μμ±μ΄ μΈμ μ΄λ»κ² λ³κ²½λλμ§ μ μ μμΌλ―λ‘ λ·°μ 리μ€λλ₯Ό μ€μ ν΄μΌν¨. 리μ€λλ₯Ό μ€μ νλ λ©μλμ @BindingAdapter
μ΄λ
Έν
μ΄μ
μ μΆκ°.
@BindingAdapter("app:timeAttrChanged")
@JvmStatic fun setListeners(
view: MyView,
attrChange: InverseBindingListener //InverseBindingListener 맀κ°λ³μλ‘ μ¬μ©.
//λ°μ΄ν° λ°μΈλ© μμ€ν
μ μμ±μ΄ λ³κ²½λμμμ μλ €μ€ ν @InverseBindingAdapter λ±μ μ¬μ©ν μ΄λ
Έν
μ΄μ
μ΄ λ¬λ¦° λ©μλ νΈμΆμ μμν μ μμ.
) {
// Set a listener for click, focus, touch, etc.
}
View κ°μ²΄μ λ°μΈλ©λ λ³μλ₯Ό νμνκΈ° μ μ λ³νν΄μΌνλκ²½μ° Converter κ°μ²΄ μ¬μ© κ°λ₯.
<EditText
android:id="@+id/birth_date"
android:text="@={Converter.dateToString(viewmodel.birthDate)}"
/>
μλ°©ν₯ λ°μ΄ν° λ°μΈλ©μ΄ μ 곡λλ―λ‘ μλ³νμ νλ κΈ°λ₯λ νμν¨.
컨λ²ν°μ @InverseMethod
μ΄λ
Έν
μ΄μ
μ μΆκ°ν ν μ΄ μ΄λ
Έν
μ΄μ
μ΄ μ컨λ²ν°λ₯Ό μ°Έμ‘°νλλ‘ ν¨.
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.
}
}
μλ°©ν₯ λ°μ΄ν° λ°μΈλ©μ μ¬μ©ν λ 무ν 루νκ° λ°μνμ§ μλλ‘ μ£Όμν΄μΌ ν¨
μ μ κ° μμ± λ³κ²½ -> @InverseBindingAdapter
κ° μ¬μ©λ λ©μλκ° νΈμΆ -> @BindingAdapter
κ° μ¬μ©λ λ©μλ νΈμΆ -> @InverseBindingAdapter
κ° μ¬μ©λ λ©μλμ λν λ λ€λ₯Έ νΈμΆ νΈλ¦¬κ±°
λ°λΌμ @BindingAdapter
κ° μ¬μ©λ λ©μλμ μ κ°κ³Ό μ΄μ κ°μ λΉκ΅νμ¬ λ¬΄ν 루νλ₯Ό λ°©μ§νλ κ²μ΄ μ€μ.
+) @BindingAdapter @InverseBindingAdapter λ΄μ© μ 리νκΈ°