I have already solved this but with a "hardcode" for 3 data sources with a solution very similar to that of this answer but this is not scalable.
Sure is, haven't you seen the EDIT? ;)
You can use the library that I wrote for this specific purpose https://github.com/Zhuinden/livedata-combinetuple-kt which does the same thing.
Now link-only answers aren't a good thing, so I'll explain what it does.
First I have tuples from 4-16 arity (because Kotlin already has Pair
and Triple
) in tuples-kt
(which I wrote so that you don't need to write so many tuples yourself)
They look like this:
data class Tuple4<A, B, C, D>(
val first: A,
val second: B,
val third: C,
val fourth: D
) : Serializable {
override fun toString(): String {
return "Tuple4[$first, $second, $third, $fourth]"
}
}
data class Tuple5<A, B, C, D, E>(
val first: A,
val second: B,
val third: C,
val fourth: D,
val fifth: E
) : Serializable {
override fun toString(): String {
return "Tuple5[$first, $second, $third, $fourth, $fifth]"
}
}
Then in LiveData-CombineTuple-KT
, there is code like this:
fun <T1, T2, T3, T4> combineTuple(f1: LiveData<T1>, f2: LiveData<T2>, f3: LiveData<T3>, f4: LiveData<T4>): LiveData<Tuple4<T1?, T2?, T3?, T4?>> = MediatorLiveData<Tuple4<T1?, T2?, T3?, T4?>>().also { mediator ->
mediator.value = Tuple4(f1.value, f2.value, f3.value, f4.value)
mediator.addSource(f1) { t1: T1? ->
val (_, t2, t3, t4) = mediator.value!!
mediator.value = Tuple4(t1, t2, t3, t4)
}
mediator.addSource(f2) { t2: T2? ->
val (t1, _, t3, t4) = mediator.value!!
mediator.value = Tuple4(t1, t2, t3, t4)
}
mediator.addSource(f3) { t3: T3? ->
val (t1, t2, _, t4) = mediator.value!!
mediator.value = Tuple4(t1, t2, t3, t4)
}
mediator.addSource(f4) { t4: T4? ->
val (t1, t2, t3, _) = mediator.value!!
mediator.value = Tuple4(t1, t2, t3, t4)
}
}
fun <T1, T2, T3, T4, T5> combineTuple(f1: LiveData<T1>, f2: LiveData<T2>, f3: LiveData<T3>, f4: LiveData<T4>, f5: LiveData<T5>): LiveData<Tuple5<T1?, T2?, T3?, T4?, T5?>> = MediatorLiveData<Tuple5<T1?, T2?, T3?, T4?, T5?>>().also { mediator ->
mediator.value = Tuple5(f1.value, f2.value, f3.value, f4.value, f5.value)
mediator.addSource(f1) { t1: T1? ->
val (_, t2, t3, t4, t5) = mediator.value!!
mediator.value = Tuple5(t1, t2, t3, t4, t5)
}
mediator.addSource(f2) { t2: T2? ->
val (t1, _, t3, t4, t5) = mediator.value!!
mediator.value = Tuple5(t1, t2, t3, t4, t5)
}
mediator.addSource(f3) { t3: T3? ->
val (t1, t2, _, t4, t5) = mediator.value!!
mediator.value = Tuple5(t1, t2, t3, t4, t5)
}
mediator.addSource(f4) { t4: T4? ->
val (t1, t2, t3, _, t5) = mediator.value!!
mediator.value = Tuple5(t1, t2, t3, t4, t5)
}
mediator.addSource(f5) { t5: T5? ->
val (t1, t2, t3, t4, _) = mediator.value!!
mediator.value = Tuple5(t1, t2, t3, t4, t5)
}
}
Written all the way from 3 up to 16. Although it is a Kotlin library, so it assumes you have the Kotlin-stdlib in your project for Pair
and Triple
.
Anyways, I'd assume the ability to combine 16 LiveData into a tuple should be sufficient for most scenarios.
If Kotlin isn't allowed, then I'm sure the relevant Kotlin logic can be translated into Java, but it'd be a lot more verbose, so I never did.
In Kotlin, you can now easily do this:
val liveData = combineTuple(liveData1, liveData2, liveData3).map { (value1, value2, value3) ->
// do something with nullable values
}
liveData.observe(this) { mappedValue ->
// do something with mapped value
}
Your example would change as follows
fun getSourceR(): MutableLiveData<Object_R>() {}
fun getSourceS(): MutableLiveData<Object_S>() {}
fun getSourceU(): MutableLiveData<Object_U>() {}
combineTuple(getSourceR(), getSourceS(), getSourceU()).map { (r, s, u) ->
sources ->
Log.d("MergeLiveData", r?.methodOf_R)
Log.d("MergeLiveData", s?.methodOf_S)
Log.d("MergeLiveData", u?.methodOf_U)
}
I advise you should try it out.