365連休

にわかのandroidとかの開発メモ。

Android Studio 3.5 AndroidX.LifecycleライブラリのViewModelとSavedStateViewModelFactoryを試してみた

AndroidX.Lifecycleドキュメントはあまり読んでないです。

 

Gradle設定

def lifecycle_version = "2.1.0"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" // ViewModel and LiveData
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // alternatively - just ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-rc02" //SavedState 執筆時 最新版

 

ViewModelは画面の状態を表すデータを管理する。

public class TestViewModel extends ViewModel {

    private MutableLiveData<string> mText;

    public TestViewModel() {
        mText = new MutableLiveData<>();
        mText.setValue("hoge");
    }

    public LiveData<string> getText() {
        return mText;
    }

}

個々のデータはLiveData<T>というクラスで表され、LiveDataにObserverを登録することで、データの変更に連動して画面項目に反映していくという作業を簡単に行うことができる。

ViewModelを使うためにはViewModelProviderから取得する必要がある。

public HogeFragment extends Fragment

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {

        //TODO:インフレート
        TextView textView;

        //ViewModelインスタンス化
        TestViewModel vm = ViewModelProviders.of(this).get(TestViewModel.class);

        //ViewModelオブザーバ登録
        vm.getText().observe(this, new Observer<string>() {
            @Override
            public void onChanged(@Nullable String s) {
                textView.setText(s); //例えばtextViewに値を設定する
            }
        });
        //データ変更
        vm.getText().postValue("fuga"); //オブザーバが反応する

    }

}

 

 ViewModelは便利だが、画面回転時のActivity再生成に対応していない。

そんな愚痴で耳にタコができたせいか、SavedStateViewModelFactoryというクラスが追加された。

注:旧クラス名SavedStateVMFactory

 

public class TestViewModel extends ViewModel {

    private MutableLiveData<String> mText;

    public TestViewModel(@NonNull SavedStateHandle savedStateHandle) {
        mText = savedStateHandle.getLiveData("mText", "hoge");
    }
/* こちらは使用しない
    public TestViewModel() {
        mText = new MutableLiveData<>();
        mText.setValue("hoge");
    }
*/
    public LiveData<String> getText() {
        return mText;
    }

}
public HogeFragment extends Fragment

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {

        //TODO:インフレート
        TextView textView;

        //ViewModelインスタンス化、owener引数=thisはFragmentActivityまたはFragmentを設定する
        TestViewModel vm = new ViewModelProvider(
                            this,
                            new SavedStateViewModelFactory(getActivity(), this)
                        ).get(TestViewModel.class);
        //TestViewModel vm = ViewModelProviders.of(this).get(TestViewModel.class);

        //ViewModelオブザーバ登録
        vm.getText().observe(this, new Observer<string>() {
            @Override
            public void onChanged(@Nullable String s) {
                textView.setText(s); //例えばtextViewに値を設定する
            }
        });
        //データ変更
        vm.getText().postValue("fuga"); //オブザーバが反応する

    }

}

 

これだけで、Activityの再生成時に値を保持してくれる。

 

だがしかし、

SavedStateViewModelFactoryが有効なのは、ユーザが入力中のテキストボックスの値など、現在のセッションでのみ扱う一時的なデータだけだと思う。

 

なぜならば、アプリで次回起動時に復元するようなデータであれば、onPauseなどユーザがアクティビティを離れるタイミングまでにSharedPreferenceに保存してしまうため、そこから復元すればよい。

むしろSavedStateHandleの値は無視しないと、2重に復元処理が走ってしまう。

 

なお、ViewModelはコンテキストと切り離されているため、通常SharedPrefereneにアクセスできない。

 

 

個人的な結論

  • SavedStateViewModelFactoryを使う場合、ViewModelで保持するデータは現在のセッションでのみ有効なものに限る。例えば手入力するテキストボックスの値。保存するデータは1MB以内
  • SavedStateViewModelFactoryを使わない場合、画面の状態を表す各種データをLiveDataで保持すると便利。

 

以上。