0

I am working on an Android application where users can save meals and their amounts according to a specific date. Time is stored as a yyyy-mm-dd string in a SQLite Database at the moment (I probably will change the data type later on). The user can select the date on a CalendarView and the RecylerView should just show the meals on the selected date. I don't want to retrieve all the rows but just query the rows depending on the date. I am using the Room Persistence Library.

How can I achieve this?

I am using a LiveData<List<MYOBJECT>> and the appropriated Observable Listener:

final MyViewModel myViewModel = ViewModelProviders.of(this).get(MyViewModel.class); 
String myDate = getDateFromCalendarView();    

myViewModel.getMealsOnDate(myDate).observe(this, new Observer<List<MYOBJECT>>() {
        @Override
        public void onChanged(@Nullable List<MYOBJECT> myObjects) {
            adapter.setItems(myObjects); // adapter from RecyclerView
        }
    });

This is the query in my DAO interface:

@Query("SELECT * FROM meals WHERE meals_date = :date")
LiveData<List<MYOBJECT>> getMealsOnDate(String date);

At the moment the Observer does not react on a different value in myDate therefore I can not query different rows from my database.

Is this even possible or do I have to stick with query the whole table and then select the data from my List<MYOBJECT?

linux_lover
  • 125
  • 1
  • 13

2 Answers2

2

Instead of making the list observable make the myDate variable observable. Because its the date that is changing and not the list. You can achieve this by:

Make your myDate as a MutabeLiveData in viewModel. Then you can change its value when date is selected from CalenderView using setValue(newDate).

Now, observer this myDate, and on value change, fetch the list with update date value and update the RecyclerView.

Also use TimeStamp instead of storing date as yyyy-mm-dd String.

***********UPDATE*************

Example for further clarification

In ViewModel class do this

MutableLiveData<String>() myDate=new MutableLiveData<String>();

In Activity do this:

calendarView.setOnDateChangeListener( new CalendarView.OnDateChangeListener() {
public void onSelectedDayChange(CalendarView view, int year, int month, int dayOfMonth) {
   myViewModel.myDate.setValue(""+year+"-"+month+"-"+dayOfMonth);//This will invoke the observer
}});

myViewModel.myDate.observe(this, new Observer<String>() {
        @Override
        public void onChanged(@Nullable String newDate) {
           //do this on dedicated thread
           List<MYOBJECT> myObjects=myViewModel.getMealsOnDate(newDate)
           adapter.setItems(myObjects); // adapter from RecyclerView
        }
    });

Note: 1.The getMealsOnDate() need not to be wrapped as LiveData. The method in Dao can return List<MYOBJECT> instead of LiveData<List<MYOBJECT>>.So you will need not to observe it.

2.Don't run the db queries on main thread, and do call the notifyDataSetChanged in setItems() of adapter to refresh the Recyclerview.

ankuranurag2
  • 2,300
  • 15
  • 30
  • That sounds like a promising idea. Unfortunately, I still can't quite imagine how I can implement this in my ViewModel. Could you give me a small example? – linux_lover Dec 28 '18 at 13:27
  • Thank you for the good example! This would mean, however, that the RecyclerView will not be updated if there is a change (e.g. a new entry). That's why I use LiveData for my list of Meals. I don't have to worry about updating with an observer. Besides, the database queries are only executed on the main thread for test purposes. I had a few problems with asynchronous execution – linux_lover Dec 28 '18 at 18:19
2

Similar question has been answered here, here and here. I am sure you'll find appropriate samples you can modify for your use cases in the links provided above.

I would do it this way: in the viewmodel I'll have a mutableLive data variable holding myDate

MutableLiveData<String>() myDate = MutableLiveData<String>();

then I have a variable for mealsOnDate

LiveData<List<MyObject>> mealsOnDate = Transformations.switchMap(myDate, (dateString -> getMealsOnDate(dateString)))

then you can observe the mealsOnDate on the activity or fragments like this

viewmodel.mealsOnDate.observe(this, new Observer<List<MyObject>>() {
        @Override
        public void onChanged(List<MyObject> list) {
            adapter.setItems(list)
        }
    });
ilatyphi95
  • 555
  • 5
  • 22