昨天建立的 ViewModel 是為了保存頁面上的資料,才不會原本在頁面上輸入一些資料,結果不小心把應用程式切到背景,或者是弄到螢幕旋轉,然後資料就全沒了。
因為 ViewModel 的初始化是使用ViewModelProvider
,所以沒辦法傳入參數,所以要建立 ViewModelFactory,先初始化 ViewModelFactory 並傳入參數,然後初始化 ViewModel 的同時把 ViewModelFactory 也一起放入。
class NoteViewModelFactory(private val 構造函數: Int) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(NoteViewModel::class.java)) {
return NoteViewModel(構造函數) as T
}
throw IllegalArgumentException("找不到 NoteViewModel")
}
}
private lateinit var viewModel: NoteViewModel
private lateinit var viewModelFactory: NoteViewModelFactory
override fun onCreateView(...): View {
viewModelFactory = NoteViewModelFactory(構造函數)
viewModel = ViewModelProvider(this, viewModelFactory)[NoteViewModel::class.java]
}
要注意的是旋轉螢幕也會被觀察到,所以有些地方要加上判斷式
MutableLiveData<>()
或LiveData<>()
,兩者差別如下可讀 | 可寫 | |
---|---|---|
MutableLiveData | O | O |
LiveData | O | X |
MutableLiveData 只要這樣寫就好
val 字串 = MutableLiveData<String>()
val 數值 = MutableLiveData<Int>()
val 布林 = MutableLiveData<Boolean>()
...以此類推
LiveData 還要加上getter
private var _字串 = MutableLiveData<String>()
val 字串: LiveData<String>
get() = _字串
private var _數值 = MutableLiveData<Int>()
val 數值: LiveData<Int>
get() = _數值
private var _布林 = MutableLiveData<Boolean>()
val 布林: LiveData<Boolean>
get() = _布林
init
內,使用.value
,之後要使用的話都要用.value
init {
字串.value = ""
數值.value = 0
布林.value = true
...
}
如果用到 ++ 或 -- ,改用minus
或plus
數值.value = 數值.value?.minus(1)
數值.value = 數值.value?.plus(1)
如果是 Int 或 String 的話,Observer可以不用加上形態,但如果是布林就要寫成Observer<Boolean>
,保險一點就是都加上形態吧
至於觀察者要建立在onCreateView
或onViewCreated
,只要用viewLifecycleOwner
,不要用this
,這樣不管寫在那裡都可以
override fun onCreateView(...): View {
viewModel.字串.observe(viewLifecycleOwner, Observer<String> { 新字串 ->
binding.TextView.text = 新字串
})
viewModel.數值.observe(viewLifecycleOwner, Observer<Int> { 新數值 ->
binding.TextView.text = 新數值.toString()
})
viewModel.布林.observe(viewLifecycleOwner, Observer<Boolean> { 新布林 ->
})
}