I have a value in the UI that it's value depends on two LiveData objects. Imagine a shop where you need a subtotal = sum of all items price
and a total = subtotal + shipment price
. Using Transformations we can do the following for the subtotal LiveData object (as it only depends on itemsLiveData
):
val itemsLiveData: LiveData<List<Items>> = ...
val subtotalLiveData = Transformations.map(itemsLiveData) {
items ->
getSubtotalPrice(items)
}
In the case of the total it would be great to be able to do something like this:
val shipPriceLiveData: LiveData<Int> = ...
val totalLiveData = Transformations.map(itemsLiveData, shipPriceLiveData) {
items, price ->
getSubtotalPrice(items) + price
}
But, unfortunately, that's not possible because we cannot put more than one argument in the map function. Anyone knows a good way of achieving this?
UPDATE
Based on my previous answer, I created a generic 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)
}
}
}
}
OLD
At the end I used MediatorLiveData to achieve the same objective.
fun mapBasketTotal(source1: LiveData<List<Item>>, source2: LiveData<ShipPrice>): LiveData<String> {
val result = MediatorLiveData<String>()
uiThread {
var subtotal: Int = 0
var shipPrice: Int = 0
fun sumAndFormat(){ result.value = format(subtotal + shipPrice)}
result.addSource(source1, { items ->
if (items != null) {
subtotal = getSubtotalPrice(items)
sumAndFormat()
}
})
result.addSource(source2, { price ->
if (price != null) {
shipPrice = price
sumAndFormat()
}
})
}
return result
}