web-dev-qa-db-ja.com

ベストプラクティス:RoomおよびLiveDataを使用したランタイムフィルター

私は、リサイクラを使用して、RoomラップされたDBの内容を表示する画面で作業しています。アダプターは、R​​oom DAOオブジェクトのクエリ呼び出しを非表示にするViewModelからLiveDataを取得します。したがって、LiveDataオブジェクトは、実際にはRoom DBの変更を認識するComputableLiveDataオブジェクトです。

次に、フィルターオプションを画面に追加します。このRoom-LiveData-ViewModelセットアップでこれをどこで/どのように実装しますか?

アダプターまたはViewModelは、LiveDataの結果を「ポストフィルター」する必要がありますか?フィルターが変更されるたびに、部屋からデータを再クエリする必要がありますか?そのために基礎となる(計算可能な)LiveDataを再利用できますか?そうでない場合、フィルターを変更するたびに新しいLiveDataを作成する必要がありますか?

同様の質問をここで説明します: Room、ViewModel、LiveData でデータを変更した後、RecyclerViewをリロードします

13
Oderik

だから、私はこのようにしてやった:

  • フラグメントは、フィルター状態をViewModelに転送します。副作用:フィルター状態は、複数の(つまり、構成変更による後続の)フラグメントインスタンスによって使用される場合があります。たぶんあなたはそれを望みます、多分そうではありません。私がやります。
  • ViewModelはMediatorLiveDataインスタンスを保持します。これには、Room DB LiveDataオブジェクトという単一のソースがあります。ソースはメディエーターへの変更を単に予告します。フラグメントによってフィルターが変更された場合、ソースは再クエリによってスワップされます。

詳細な質問に答える:

  • ポストフィルタリングなし
  • はい、フィルター変更の再クエリ
  • ComputableLiveDataを再利用しません(可能かどうかはわかりません)

コメントの議論について:

  • ページングを適用しません

ルームに関する最後の注意:私は間違っていますか、または適用したいすべてのフィルターの組み合わせに対して別々のDAOメソッドを記述する必要がありますか? OK、選択ステートメントのオプション部分を文字列を介して挿入できますが、それからルームの利点を失います。ステートメントを構成可能にするステートメントビルダーのようなものがいいでしょう。

編集:以下のRidcullyによるコメントに注意してください。彼は、私が推測する最後の部分に対処するために、@ RawQueryとともにSupportSQLiteQueryBuilderに言及しています。私はまだそれをチェックアウトしませんでした。

CommonsWarepskink に感謝します!

4
Oderik

私は同様の問題に取り組んでいます。最初はRxJavaを使用していましたが、現在はLiveDataに変換しています。

これは私が私のViewModelの中でやっている方法です:

// Inside ViewModel
MutableLiveData<FilterState> modelFilter = new MutableLiveData<>();
LiveData<PagedList<Model>> modelLiveData;

このmodelLivedataは、ビューモデルコンストラクター内で次のように構築されます。

        // In ViewModel constructor
        modelLiveData = Transformations.switchMap(modelFilter,
                    new Android.Arch.core.util.Function<FilterState, LiveData<PagedList<Model>>>() {
                        @Override
                        public LiveData<PagedList<Model>> apply(FilterState filterState) {
                            return modelRepository.getModelLiveData(getQueryFromFilter(filterState));
                        }
                    });

ビューモデルは、適用される別のフィルターを受け取ると、次のことを行います。

// In ViewModel. This method receives the filtering data and sets the modelFilter 
// mutablelivedata with this new filter. This will be "transformed" in new modelLiveData value.
public void filterModel(FilterState filterState) {

    modelFilter.postValue(filterState);
}

次に、この新しいフィルターは、オブザーバー(フラグメント)に送信される新しいlivedata値に「変換」されます。

フラグメントは、ビューモデルの呼び出しを通じて監視するライブデータを取得します。

// In ViewModel
public LiveData<PagedList<Model>> getModelLiveData() {

    return modelLiveData;

}

そして、私のフラグメントの中に私は持っています:

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    ViewModel viewModel = ViewModelProviders.of(this.getActivity()).get(ViewModel.class);

    viewModel.getModelLiveData().observe(this.getViewLifecycleOwner(), new Observer<PagedList<Model>>() {
        @Override
        public void onChanged(@Nullable PagedList<Model> model) {
            modelListViewAdapter.submitList(model);
        }
    });

}

役に立てば幸いです。

13