enumsandroid-roomandroid-livedatalong-integerandroid-viewmodel

Android: Filter CardViews in RecyclerView List with Room DAO


I have a RecylcerView List of CardViews. Each CardView holds user data that is saved in a Room database. Some of the CardViews have due dates that have been entered by the user with a TimePicker. I set up a filterButton to filter the full List by passing a Long for the entered due date from the TimePicker.

I try to pass the Long from the Activity to the ViewModel, then to Repository and then to the DAO. The DAO method should return all CardViews with due dates that are on or before the entered due date. The full List is returned, so the filtering is not working. I chose a Long so that a null value can be passed for the due date for the initial sorting of the full List. The initial sorting is based on a SortOrder criteria in the database.

Is the enum in the Respository keeping the Long from being passed to the DAO method? What am I missing here?

Activity
//filterButton press
Calendar cal = Calendar.getInstance();
duedate5 = cal.getTimeInMillis // the date selected by the user in the TimePicker.
Long duedate5Long = duedate5;  // convert the long to a Long so null can be used for this date parameter on the initial List sort.      
mViewModel.setSortOrder(Repository.SortOrder.DB_FILTONORBEF, **duedate5Long**);


ViewModel
public class ViewModel extends AndroidViewModel {
    ...
    public ViewModel(@NonNull Application application) {
       
       repository = new Repository(application);
       // set the initial sort, using the SortOrder field in the database and
       // no due date is passed.
       setSortOrder(Repository.SortOrder.DB_SORTORDER,null);  

       public void setSortOrder(Repository.SortOrder newOrder, **Long duedate5**) {

           LiveData<List<Card>> newSource = repository.getSortedItems(newOrder, **duedate5**); 
           ...
        }
    }


Repository
public class Repository {
     
    private final CardDao cardDao;
  
    public Repository(Application application) {
        CardRoomDatabase db = CardRoomDatabase.getDatabase(application);
        cardDao = db.cardDao();
    }        

    public LiveData<List<Card>> getSortedItems(SortOrder order, **Long duedate5**) {

        switch (order) {
            case DB_SORTORDER:
                return cardDao.getAllCards();
            case DB_FILTONORBEF:
                return cardDao.getFiltOnOrBeforeList(**duedate5**);
        }
    }

    public enum SortOrder {
    
        DB_SORTORDER,
        DB_FILTONORBEF
    }   

    
CardDao
@Dao
public interface CardDao {
        
    // For filtering the full RecyclerView List On or Before the entered Due date.
    @Query("SELECT * FROM cards_table WHERE CardDuedatentime !=-1 AND" +   
           "CardDuedatentime < :dueDate5 ORDER BY CardDuedatentime ASC")
    LiveData<List<Card>> getFiltOnOrBeforeList(Long dueDate5);

}

   

Solution

  • Looking at your question, I can identify several potential issues with the filtering implementation:

    1. SQL Query Logic Problem

    The most likely culprit is in your DAO query:

    WHERE CardDuedatentime !=-1 AND CardDuedatentime < :dueDate5
    

    You're using < (less than) but you said you want cards "on or before" the date. This should be <= (less than or equal to):

    WHERE CardDuedatentime !=-1 AND CardDuedatentime <= :dueDate5
    

    2. Missing Return Statement in Repository

    Your getSortedItems method doesn't have a default return case:

    public LiveData<List<Card>> getSortedItems(SortOrder order, Long duedate5) {
        switch (order) {
            case DB_SORTORDER:
                return cardDao.getAllCards();
            case DB_FILTONORBEF:
                return cardDao.getFiltOnOrBeforeList(duedate5);
        }
        // Missing return statement here - this shouldn't compile
        return null; // or throw an exception
    }
    

    3. Potential Time Zone Issues

    When you get the time from the Calendar:

    Calendar cal = Calendar.getInstance();
    duedate5 = cal.getTimeInMillis();
    

    Make sure this matches how you're storing dates in the database. If you're using a DatePicker/TimePicker, you might need to set the specific date/time components:

    Calendar cal = Calendar.getInstance();
    cal.set(year, month, day, hour, minute, 0);
    cal.set(Calendar.MILLISECOND, 0);
    long duedate5 = cal.getTimeInMillis();
    

    4. Verify Database Values

    The -1 check suggests you're using -1 as a sentinel value for "no due date". Make sure:

    Debugging Suggestions:

    1. Add logging to verify the value being passed:
    // In Repository
    public LiveData<List<Card>> getSortedItems(SortOrder order, Long duedate5) {
        Log.d("Repository", "Filter date: " + duedate5);
        // ... rest of code
    }
    
    1. Test the query directly in Room's database inspector or by creating a test method:
    @Query("SELECT * FROM cards_table WHERE CardDuedatentime !=-1")
    LiveData<List<Card>> getAllCardsWithDueDates();
    
    1. Check if the LiveData is updating - sometimes the issue is with observation, not the query itself.

    The enum itself shouldn't be preventing the Long from being passed - it's just being used for the switch statement logic. The most likely issue is the SQL comparison operator or a mismatch in how dates are being stored vs queried.