Databinding 與 Observable
目前爲止我們已經實現了透過 Databinding 完成數據綁定的方式,但是每次當數據改變時(例如:api 的 response 回來了),都要重新向 ViewDataBinding 傳遞新的數據並刷新 UI,有沒有辦法能做到數據更新後 UI 也能 自動 刷新呢,答案就是透過 觀察者模式,也就是本篇的重點 Observable
,這是 Databinding 支持的庫,而且使用起來也非常方便。
這裡我來做一個計時器能定時對 ViewModel 發送數據,並讓 UI 能夠同步更新
layout 很簡單,一個 TextView 來顯示 ViewModel 裡的 num
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(viewModel.num)}" />
每隔兩秒都向 ViewModel 發送數據,發送完後的 num 都會再加一,方便我知道下次更新 ViewModel 時 UI 到底有沒有更新
Timer().schedule(object : TimerTask() {
override fun run() {
viewModel.updateNumber(num++)
}
}, 0, 2000)
原本的 ViewModel 是沒辦法自動更新 UI 的
fun updateNum(num: Int) {
this.num = num //沒作用
}
讓 ViewModel 繼承 BaseObservable()
並在想要觀察的變數上面加上 Bindable
註解,這步就能夠將這個變數和 UI 層綁定在一起
class MainViewModel : BaseObservable() {
@Bindable
var num: Int = 0
}
最後在數據丟過來的地方呼叫 BaseObservable 的 notifyChange()
就成功囉
fun updateNum(num: Int) {
this.num = num
notifyChange()
}
這個 notifyChange()
是通知 databinding 把所有已綁定的數據更新一次,BaseObservable 還有另一個方法notifyPropertyChanged
是只用來更新某一個變數的
notifyPropertyChanged(BR.num)
這個 BR
不是指文湖線 是 databinding 自動生成的類似 R
檔用來放 id 的檔案,加上 @Bindable
註解的變數記得要 Make Project 後才會生成在 BR
檔裡面
fun updateData(title: String, content: String) {
this.content = content
this.title = title
notifyPropertyChanged(BR.title)//只有 title 會更新
}
這個 notifyChange 很有似曾相識的感覺,很像 RecyclerView.Adapter 的 notifyDataSetChanged
,
為了不要每次更新時都要呼叫一次這個 fun ,databinding 很貼心的當我們設計了 ObservableField
這個類
這個類接的是一個泛型,只要把原本的變數包起來就可以不用再每次呼叫 notifyChange
var num = ObservableField<Int>()
原本的 assign 改成 set
this.num.set(num)
其他還有一些很類似的例如: ObservableBoolean
,ObservableInt
...都是大同小異的東西,可以視需求或是讓代碼更簡潔自行替換。
藉由這樣的操作,View 層只需要呼叫 ViewModel 改變數據,不需要接收任何數據更改完成的 callback,
完成了先前提到的響應式 UI。
有任何問題或講得不清楚的地方歡迎留言和我討論。
更歡迎留言糾正我任何說錯的地方!
下一篇:Databinding (六) RecyclerView