アプリ開発備忘録

PlayStationMobile、Android、UWPの開発備忘録

【Android】SavedStateHandleでViewModelをプロセスキルを乗り越えるようにする

I/Oセッション

youtu.be

ViewModel

このようなカウントするLiveDataがあります。

class MainViewModel : ViewModel() {
   val counter = MutableLiveData(0)
}

押したら1増やします。
ViewModelを使用すれば画面回転を乗り越えられます。
f:id:matsudamper:20190530061954p:plain

当たり前ですが、プロセスキルまでは乗り越えることができません。
いままではこの様なコードを書く必要がありました。

override fun onSaveInstanceState(outState: Bundle) {
   super.onSaveInstanceState(outState)
   viewModel.counter.value?.also { outState.putInt("counter", it) }
}

override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
   super.onRestoreInstanceState(savedInstanceState)
   savedInstanceState ?: return
   viewModel.counter.value = savedInstanceState.getInt("counter")
}

それを楽にするのがSavedStateHandleです。

SavedStateHandle

dependencies

implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-alpha01"

LiveData

LiveDataを以下のように書き換えます。
コンストラクタにSavedStateHandleを指定します。
keyを引数にしてLiveDataを取得します。
SavedStateHandleはKey-Valueオブジェクトのようになっています。

class MainViewModel(
   handle: SavedStateHandle
) : ViewModel() {
   val counter: MutableLiveData<Int> = handle.getLiveData("counter")
}

Activity Fragment

ViewModelを取得する部分にKTXができましたので使います。

implementation "androidx.activity:activity-ktx:1.0.0-alpha08"
implementation "androidx.fragment:fragment-ktx:1.1.0-alpha09"

ViewModelを取得します専用のViewModelFactoryがあるのでそれを使います。
このSavedStateVMFactoryは第一引数にApplicationを指定すると解決してくれます。これでAndroidViewModelも使えます。

private val viewModel by viewModels<MainViewModel> () {
    SavedStateVMFactory(this)
}

自分でViewModelFactoryを作りたい場合はAbstractSavedStateVMFactoryを継承してください。

初期値

初期値を指定する場合、以下のようにBundleに入れてあげます。

private val viewModel by viewModels<MainViewModel> {
    SavedStateVMFactory(this, Bundle().apply {
        putInt("counter", 0)
    })
}

おわり

SavedStateHandleを使用するとプロセスキルを乗り越えられるViewModelを作成することができます。
結局はonSaveInstanceStateを使用しているので大きいデータは保存することができないのが注意です。idなどを保存してDBから取得するようにしましょう。