Best practice: Runtime filters with Room and LiveData

时间秒杀一切 提交于 2019-12-03 16:21:55

问题


I am working on a screen that shows the contents of a Room wrapped DB using a recycler. The adapter gets the LiveData from a ViewModel that hides the query call on the Room DAO object. So, the LiveData object is actually a ComputableLiveData object that is aware of changes to the Room DB.

Now I want to add filter options to the screen. Where / how would I implement this in this Room-LiveData-ViewModel setup?

Should the adapter or ViewModel "postfilter" the results in the LiveData? Should I requery the data from room for every filter change? Can I reuse the underlying (Computable)LiveData for that? If not, should I really create new LiveData for every filter change?

A similar question is discussed here: Reload RecyclerView after data change with Room, ViewModel and LiveData


回答1:


I'm working in a similar problem. Initially I had RxJava but now I'm converting it to LiveData.

This is how I'm doing inside my ViewModel:

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

This modelLivedata is constructed in the following way inside view model constructor:

        // 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));
                        }
                    });

When the view model receives another filter to be applied, it does:

// 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);
}

Then, this new filter will be "transformed" in a new livedata value which will be sent to the observer (a fragment).

The fragment gets the livedata to observe through a call in the view model:

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

    return modelLiveData;

}

And inside my fragment I have:

@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);
        }
    });

}

I hope it helps.




回答2:


So, I ended up doing it like this:

  • The fragment fowards the filter state to the ViewModel. Side effect: the filter state may be used by multiple (i.e. subsequent due to configuration change) fragment instances. Maybe you want that, maybe not. I do.
  • The ViewModel holds a MediatorLiveData instance. It has a single source: The Room DB LiveData object. The source simply forards changes to the mediator. If the filter is changed by the fragment, the source is swapped by a requery.

Answering my detailed questions:

  • No postfiltering
  • Yes, requery on filter change
  • I don't reuse the ComputableLiveData (not sure wether it would be possible)

Regarding the discussion in the comments:

  • I don't apply paging

Final note on Room: Am I wrong or do I need to write seperate DAO methods for every filter combination I want to apply? Ok, I could insert optional parts of the select statement via a String, but then I would lose the benefits of Room. Some kind of statement builder that makes statements composable would be nice.

EDIT: Please note the comment by Ridcully below. He mentions SupportSQLiteQueryBuilder together with @RawQuery to address the last part I guess. I didn't check it out yet though.

Thanks to CommonsWare and pskink for your help!



来源:https://stackoverflow.com/questions/48769812/best-practice-runtime-filters-with-room-and-livedata

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!