I have two DAOs, two Repositories and two POJOs. There is some way to create one Livedata of two? I need it to make single list for Recyclerview. POJOs are similar objects.<
Instead of having a class to add 2 live datas, another class to add 3 live datas, etc. We can use a more abstract way where we can add as many live datas as we want.
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
/**
* CombinedLiveData is a helper class to combine results from multiple LiveData sources.
* @param liveDatas Variable number of LiveData arguments.
* @param combine Function reference that will be used to combine all LiveData data.
* @param R The type of data returned after combining all LiveData data.
* Usage:
* CombinedLiveData<SomeType>(
* getLiveData1(),
* getLiveData2(),
* ... ,
* getLiveDataN()
* ) { datas: List<Any?> ->
* // Use datas[0], datas[1], ..., datas[N] to return a SomeType value
* }
*/
class CombinedLiveData<R>(vararg liveDatas: LiveData<*>,
private val combine: (datas: List<Any?>) -> R) : MediatorLiveData<R>() {
private val datas: MutableList<Any?> = MutableList(liveDatas.size) { null }
init {
for(i in liveDatas.indices){
super.addSource(liveDatas[i]) {
datas[i] = it
value = combine(datas)
}
}
}
}
I assume you want to combine them, yes? You'll need a MediatorLiveData, but the guy saying you now need Object is wrong. What you need is a MediatorLiveData<Pair<List<Expense>, List<Income>>>
.
public class CombinedLiveData extends MediatorLiveData<Pair<List<Expense>, List<Income>>> {
private List<Expense> expenses = Collections.emptyList();
private List<Income> incomes = Collections.emptyList();
public CombinedLiveData(LiveData<List<Expense>> ld1, LiveData<List<Income>> ld2) {
setValue(Pair.create(expenses, incomes));
addSource(ld1, expenses -> {
if(expenses != null) {
this.expenses = expenses;
}
setValue(Pair.create(expenses, incomes));
});
addSource(ld2, incomes -> {
if(incomes != null) {
this.incomes = incomes;
}
setValue(Pair.create(expenses, incomes));
});
}
}
You could potentially make this generic and it'd be the implementation of combineLatest
for two LiveData using tuples of 2-arity (Pair).
EDIT: like this:
public class CombinedLiveData2<A, B> extends MediatorLiveData<Pair<A, B>> {
private A a;
private B b;
public CombinedLiveData2(LiveData<A> ld1, LiveData<B> ld2) {
setValue(Pair.create(a, b));
addSource(ld1, a -> {
if(a != null) {
this.a = a;
}
setValue(Pair.create(a, b));
});
addSource(ld2, b -> {
if(b != null) {
this.b = b;
}
setValue(Pair.create(a, b));
});
}
}
Beware that I lost the ability to set Collections.emptyList()
as initial values of A
and B
with this scenario, and you WILL need to check for null
s when you access the data inside the pair.
EDIT: You can use the library https://github.com/Zhuinden/livedata-combinetuple-kt which does the same thing.
Let's say you want to merge LiveData<List<Expense>>
& LiveData<List<Income>>
then, you'll need to take MediatorLiveData<Object>
(why? because, both of your live data are of different types).
So, use code like below :
LiveData liveData1 = getAllExpensesByDay();
LiveData liveData2 = getAllIncomesByDay();
MediatorLiveData liveDataMerger = new MediatorLiveData<Object>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
If you need to use specific data from MediatorLiveData
then use Transformations on that.
Check out more here