ViewModel, Room, LiveData, RecyclerView filter data

1.8k Views Asked by At

I'm working on an inventory application based on Architecture components (ViewModel/Room/Livedata) and RecyclerView. The app based on the practise that Google recommends in Developer training book.
Advanced Android Development Course - Working with Architecture Components: Room, LiveData, ViewModel

The app has quite complex data model which implemented as Room entities and relations (10+ tables, foreign keys etc.). I have the corresponding DAOs as well.

The main activity is a RecyclerView of the list of items to work with and when user clicks on one of the item a special SubActivity opens and user has to enter item-related data which is saved into Room. As user goes back to the MainActivity data refreshed thanks to LiveData. Also configuration changes work thanks to ViewModel.

The application's workflow is the following:

  1. User downloads data from the server, Room DB created and the MainActivity shows the list of items to work with
  2. User browsing items, clicks on one of them, an item-specific SubActivity opens where user records its data which saved into Room
  3. When all items finished user uploads item-recorded data to server, data in Room deleted, user can download new list of items
  4. User cannot delete or insert new item on, he can only record its data in the corresponding SubActivity. Items deleted/inserted when downloading data.

What I want is to filter the list of items on the MainActivity's RecyclerView.

Google and Stackowerflow posts recommends Livedata's switchmap for filtering.
Best practice: Runtime filters with Room and LiveData
Android Room LiveData select query parameters

I don't like this approach because

  1. I have to go to Room and query data in a new AsyncTask
  2. Room doesn't provide comprehensive query based on complex filter model

    public abstract class DAO {
        @Transaction
        @Query("select * " +
                "from table1 t1 " +
                "join table2 t2 on t2.field = t1.field " +
                "join table3 t3 on t3.field = t2.field " +
                ...
                "join tablen tn on tn.field = t(n-1).field " +
                "where t1.filterField = filterData.filterField1 " +
                       and t2.filterField = filterData.filterField2 " +
                   ...
                   and tm.filterField = filterData.filterFieldm")
        public abstract LiveData<List<ComplexData>> getFilteredComplexData(FilterData filterData);
    }
    

where FilterData is a POJO.

Instead I have to write

@Transaction
@Query("select * ...")
public abstract LiveData<List<ComplexData>> getFilteredComplexData(filterField1, filterField2, ...);

My plan is the following

  1. User specifies the FilterData in FilterActivity
  2. When FilterActivity finishes

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == INTENT_REQUEST_FILTER) {
            if (resultCode == RESULT_OK) {
                FilterData filterData = (FilterData)data.getParcelableExtra(INTENT_MESSAGE_FILTER_DATA));
                RecyclerviewAdapter.setComplexData(ViewModel.getComplexData().getValue(), filterData);
            }
        }
    }
    
  3. In RecyclerView's adapter

    void setComplexData(List<ComplexData> complexData, FilterData filterData) {
        if (filterData != null) {
            List<ComplexData> = complexData.
                    stream().
                    filter(do filterData.filter1 here).
                    filter(do filterData.filter2 here).
                    ...
                    filter(do filterData.filterm here).
                    collect(Collectors.toList());
        }
        else {
            List<ComplexData> = complexData;
        }
        notifyDataSetChanged();
    }

So keep all data in LiveData and when user filters then fill up RecyclerView's adapter with filtered list and notify about changes.

Is it correct to filter in this way? Does it have any pitfall?

0

There are 0 best solutions below