由於步驟非常麻煩,找資料也要找很久,因為用的是AndroidViewModel所以寫在這邊紀錄
這篇文章給了很大的幫助
主要是如果你的dataSouce中需要用到application context跟其他物件,就必須透過Factory來進營建立,而不能自己透過建構子產生
- 將viewModel繼承 AndroidViewModel
2. 在Fragment中定義viewModel
可是如果你的viewModel需要傳入其參數,就必須建立Factory才能產生
1.增加你要的參數
2.開始繼承ViewModelProvider.AndroidViewModel…建立Factory
class FooViewModelFactory(val application: Application, val foo: Foo): ViewModelProvider.AndroidViewModelFactory(application) {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return FooViewModel(
application, foo
) as T
}
}
注意這邊要透過轉型為 as T ,非常特別的寫法
3.在fragment中建立viewModel
val viewModel = ViewModelProvider(this, FooViewModelFactory(application, foo)).get(FooViewModel::class.java)
如此就可以建立出一個具有androidViewModel並且帶有參數的ViewModel了
p.s 這是google官方sunflow的 sample
class PlantDetailViewModelFactory(
private val plantRepository: PlantRepository,
private val gardenPlantingRepository: GardenPlantingRepository,
private val plantId: String
) : ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return PlantDetailViewModel(plantRepository, gardenPlantingRepository, plantId) as T
}
}
也提供參考
最後補充
為什麼一定要用ViewModelProvider來產生viewModel?
你可能覺得奇怪,為什麼要用所謂provider來取得viewModel,為什麼不直接new 一個就好了呢 ?
先說結論
主要是他可以透過lifecycle的機制,讓你在旋轉或是離開畫面的時候,將你viewModel 裡面的變數liveData自動儲存起來,將這個Activity與這個viewModel做成一個關聯丟到系統中viewModelProvider的pool,然後在你旋轉後,自動透過provider可以去pool裡面詢問有沒有已經存在的viewModel,取出後的恢復成原本的變數使用
在簡化一下上面說的
- A Activity中產生 A ViewModel
- Provider中的ViewModel pool檢查有沒有存在的viewModel,沒有就透過A Activity對應產生一個A ViewModel,並且記憶起來
- 產生後頁面正常產生一些viewModel中的變數變動,譬如 name 在ui操作中改變為 “Hello World”
- 直到要旋轉頁面時候,由lifecycle觸發告知ViewModelProvider,這時候就自動把A Activity中的A ViewModel更新存入 pool中,直到得知destory才把他清掉
- A Activity旋轉後回到onCreate中,透過viewModelProvider詢問要有沒既有的A ViewModel,provider找到後就回傳了旋轉前的viewModel,並且name的欄位保留上次的”Hello World”
- Activity取得後將viewModel塞入view Binding中,恢復了原本的ui狀態,這時候就可以看到UI上可以寫著上次旋轉前的”Hello World”
- 結束
來看看程式碼
可以看一下他本身的get方法裡面,有一個所謂的ViewModelStore的類別
透過他就可以幫你把目前的viewModel與目前的變數key value儲存起來,那他是一個什麼
private final ViewModelStore mViewModelStore;
看一下內部,他其實就是一個hashMap用來儲存目前所有viewModel狀態的類別,細項可以繼續追下去,所以如果你想要一次清除所有的viewModel狀態就可以透過viewModelPrivoder.clear()一次把所有清除,但這只會把所有Activity的viewModel清除
以上這就是為什麼要用Provider來取得viewModel的原因,而不能自己使用new的方式來產生了,綜合以上說法,其實viewModel 的constructor本身應該是要被設定為private constructor才對,一律透過Factory來產生,才能避免對於這不懂的開發者誤用囉
done.