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
StateFlow and LiveData have similarities. Both are observable data holder classes, and both follow a similar pattern when used in your app architecture. The StateFlow and LiveData do behave differently: StateFlow requires an initial state to be passed into the constructor, while LiveData does not.
This function is deprecated. If LiveData already has data set, it will be delivered to the onChanged. The observer will only receive events if the owner is in Lifecycle.
By using LiveData we can only observe the data and cannot set the data. MutableLiveData is mutable and is a subclass of LiveData. In MutableLiveData we can observe and set the values using postValue() and setValue() methods (the former being thread-safe) so that we can dispatch values to any live or active observers.
Attach the Observer object to the LiveData object using the observe() method. The observe() method takes a LifecycleOwner object. This subscribes the Observer object to the LiveData object so that it is notified of changes. You usually attach the Observer object in a UI controller, such as an activity or fragment.
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.
So, I ended up doing it like this:
Answering my detailed questions:
Regarding the discussion in the comments:
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With