Smile Engineering Blog

ジェイエスピーからTipsや技術特集、プロジェクト物語を発信します

【Android】SavedStateHandle解説

今回は、AndroidのSavedStateHandleを解説します。

SavedStateHandle クラスは、set() メソッドおよび get() メソッドを介して、SavedState との間でデータの書き込みや取得を行えるようにする Key-Value マップです。また、getLiveData() を使用して LiveData オブザーバブルにラップされている値を SavedStateHandle から取得できます。キーの値が更新されると、LiveData が新しい値を受け取ります。

build.gradledependencies では、以下を必要とします。

implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version")

使用例

例えば、以下のように使用します。

class MainViewModel(
    // ViewModelの第1引数にSavedStateHandleを指定します。
    private val handle: SavedStateHandle
) : ViewModel() {

    companion object {
        // 値の出し入れに使用するキーを定数宣言します。
        private const val KEY_COUNT = "count"
    }

    // SavedStateHandleからキーKEY_COUNTにひも付くMutableLiveDataを探して取り出します。
    // 存在しない場合は新しく作ります。
    // そして、SavedStateHandle内でキーKEY_COUNTに対してひも付けます。
    // 初期値0。
    private val _count = handle.getLiveData(KEY_COUNT, 0)
    val count: LiveData<Int> get() = _count

    fun countUp() {
        // _count.valueはInt?型ですが、SavedStateHandle#getLiveData呼び出し時に初期値を設定しており、
        // nullが入り込むことがありません。よって、!!によって強制的にアンラップしています。
        val currentCount = _count.value!!

        // SavedStateHandle#getLiveDataにて値を取り出している場合、
        // SavedStateHandle#setで値の格納と同時に監視者への更新通知が行われます。
        // なお、SavedStateHandle#getにて値を取り出している場合には、
        // 監視者への更新通知が行われません。
        // また、内部的にはMutableLiveData#setValueが呼ばれているため、
        // ワーカースレッドから呼び出してはいけません。
        handle.set(KEY_COUNT, currentCount + 1)
    }

また、ViewModel の取得でby viewModels() を使用している場合、viewModels()ViewModelSavedStateHandleインスタンスを渡しているため、コードを変更する必要はありません。

class MainFragment : Fragment(R.layout.main_fragment) {
    private val viewModel: MainViewModel by viewModels()

参考

ViewModel の保存済み状態のモジュール