ViewModel
該怎麼做ViewModel
在創建時,都是透過 ViewModelProviders
這個類來生成
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
那需要傳遞參數給 ViewModel
時就不能透過 constructor 來傳。
Solution:
創建一個 ViewModelFactory
輔助類,並繼承 NewInstanceFactory
,這時候就可以把想要傳給ViewModel
的參數放在 constructor,例如:把 MainRepository
傳進來。
class ViewModelFactory constructor(private val repository: MainRepository) : ViewModelProvider.NewInstanceFactory() {
...
}
接著覆寫裡面的 create 方法,這裡去判斷 ViewModelProvider 接到的 ViewModel 是哪一個 class,
並返回相對應的 ViewModel,這裡返回的 ViewModel 就可以放進任何想要的參數了
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
with(modelClass) {
when {
isAssignableFrom(MainViewModel::class.java) -> MainViewModel(repository)
else ->
throw IllegalArgumentException(
"Unknown ViewModel class: ${modelClass.name}")
}
} as T
這裡如果有多個 ViewModel 共用 repository 的話,在 when 裡面增加判斷式就可以使用了。
其實 ViewModelProvider 裡面還有另一個 ViewModelProvider.Factory
可以用,和NewInstanceFactory
的差別在於,ViewModelProvider.Factory
每次都會重新創建一個新的 ViewModel, NewInstanceFactory
則是同一個實例,這個知道一下就好了,可能某些特殊情況才會用到 ViewModelProvider.Factory
。
將 Activity 創建 ViewModel 的代碼
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
修改成
val factory = ViewModelFactory(MainRepository())
viewModel = ViewModelProviders.of(this,factory).get(MainViewModel::class.java)
多丟一個 factory
參數進去而已,接著就可以把 constructor 改成想要的樣子了。
class MainViewModel(private val repository: MainRepository) : ViewModel() {
以往 Fragment 之間要傳遞數據,得依賴他們的 parent Activity 當作媒介來從 Fragment A 傳遞數據到 Fragment B,還得小心配置變更時可能把數據丟失的麻煩。
現在能夠透過使用 ViewModel
來達成 Fragment 之間共享數據,而且使用的方式非常簡單
只需要將需要共享數據的 Fragment 裡面的
viewModel = ViewModelProviders.of(this).get(FragmentViewModel::class.java)
改成
viewModel = activity?.run {
ViewModelProviders.of(this).get(FragmentViewModel::class.java)
} ?: throw Exception("Invalid Activity")
其實只是把丟給 ViewModelProviders 的實例從 Fragment 換成 Activity 而已
這時候 ViewModel 的生命週期就會依賴於 Acitvity,進而讓 Fragment 共同持有。
剛開始對 ViewModel 的認知就是透過觀察者模式實現數據變動時 UI 層可以感知到變化,那時候想說,不就好像是丟一個 callback 給 ViewModel,成功要到數據再叫回來嗎?好像沒什麼特別的。
的確只看這部分的話, ViewModel 跟 callback 有超過 87% 的相似度,但是 ViewModel 還有更多的優點
Databinding
、LiveData
實現響應式 UI所謂 響應式 UI 就是數據變動時 UI 層不只可以感知到變化,而且會自動更新
,非常的炫砲!
有任何問題或講得不清楚的地方歡迎留言和我討論。
更歡迎留言糾正我任何說錯的地方!
下一篇開始,來看看如何使用 Databinding 實現響應式 UI。