iT邦幫忙

2022 iThome 鐵人賽

DAY 16
0
Mobile Development

聽說 HackMD 開放 API 串接,那麼用 Kotlin 寫個筆記 App 吧!系列 第 16

111/16 - 資料綁定(2/2) - ViewModelFactory、LiveData

  • 分享至 

  • xImage
  •  

開頭

昨天建立的 ViewModel 是為了保存頁面上的資料,才不會原本在頁面上輸入一些資料,結果不小心把應用程式切到背景,或者是弄到螢幕旋轉,然後資料就全沒了。

因為 ViewModel 的初始化是使用ViewModelProvider,所以沒辦法傳入參數,所以要建立 ViewModelFactory,先初始化 ViewModelFactory 並傳入參數,然後初始化 ViewModel 的同時把 ViewModelFactory 也一起放入。

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")
    }
}

在 Fragment 中初始化

private lateinit var viewModel: NoteViewModel
private lateinit var viewModelFactory: NoteViewModelFactory

override fun onCreateView(...): View {
    viewModelFactory = NoteViewModelFactory(構造函數)
    viewModel = ViewModelProvider(this, viewModelFactory)[NoteViewModel::class.java]
}

LiveData

要注意的是旋轉螢幕也會被觀察到,所以有些地方要加上判斷式

  1. 把 ViewModel 的變數都改成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() = _布林
  1. 變數初始化寫在init內,使用.value,之後要使用的話都要用.value
init {
    字串.value = ""
    數值.value = 0
    布林.value = true
  ...
}

如果用到 ++ 或 -- ,改用minusplus

數值.value = 數值.value?.minus(1)
數值.value = 數值.value?.plus(1)
  1. 建立觀察者

如果是 Int 或 String 的話,Observer可以不用加上形態,但如果是布林就要寫成Observer<Boolean>,保險一點就是都加上形態吧

至於觀察者要建立在onCreateViewonViewCreated,只要用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> { 新布林 ->
        
    })
}

上一篇
111/15 - 資料綁定(1/2) - ViewModel、Layout 改寫
下一篇
111/17 - Room(1/4) - Data class、Entity
系列文
聽說 HackMD 開放 API 串接,那麼用 Kotlin 寫個筆記 App 吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言