With my current app, the main data is Subjects, where each Subject have multiple Reminders tied to it. For this purpose, I have a couple of tables in the database, which in its simplified form can be seen as below:
Subject table with:
- Subject ID
- Subject title
Reminder table with:
- Reminder ID
- Reminder timestamp
- Subject ID
I’m using Room for database and LiveData to pull data from the tables. The data then gets supplied to a RecyclerView, where each RecyclerView item will display a Subject with its Reminders.
The tricky part is that, since there are two tables, I have two separate methods returning LiveData object from each table. Most tutorials out there assume the use of only one LiveData to be observed by the RecyclerView, so it can get confusing when there’s two LiveData at once.
I found a smart solution on Stack Overflow that makes use of MediatorLiveData and Kotlin’s Pair to make the whole thing work. This article is an attempt to expand on that solution by writing down my understanding of it.
This article assumes familiarity with Android concepts for RecyclerView, Room, ViewModel, and LiveData.
Create a “combination” MediatorLiveData class
The first thing to do is to create a class that extends MediatorLiveData. The interesting part is that we need to use
Pair<List<Subject>, List<Reminder>> as MediatorLiveData’s type.
After that, we simply construct the class by sending it
LiveData<List<Reminder>> as constructor parameters, then put those two inside a
Pair, and finally set the
Pair as the
MediatorLiveData object’s value.
That is pretty much where the magic lies. The potentially tricky part is the
addSource method and the
value variable, both of which are built-in features of the MediatorLiveData.
Inside the ViewModel, we call the repository’s methods for pulling LiveData from each table, then we return a “combination” object as we describe in the class above, and put in the LiveData as its parameters.
Inside the adapter, we modify its constructor to accept two Lists as parameters, the
List<Subject> and the
Observe the MediatorLiveData
Finally, inside the fragment or activity that has the RecyclerView, we observe the returned MediatorLiveData from the ViewModel. When there’s any change, the observer gives a Pair containing a
List<Subject> and a
List<Reminder>. We can then put those two as the parameter of the adapter.
Note how the Observer pattern uses a lambda with
subjectsAndRemindersPair as the parameter. That is essentially the type of the MediatorLiveData in question, and by default Kotlin call that parameter
it. I renamed it to
subjectsAndRemindersPair to make it easier to understand.