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<Subject>>
and 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 ViewModel
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 RecyclerViewAdapter
Inside the adapter, we modify its constructor to accept two Lists as parameters, the List<Subject>
and the List<Reminder>
.
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.