带有多个参数的LiveData Transformations.map()

时间:2017-11-30 11:53:45

标签: android android-livedata android-viewmodel

我在UI中有一个值,它的值取决于两个LiveData个对象。想象一下你需要subtotal = sum of all items pricetotal = subtotal + shipment price的商店。使用Transformations我们可以对小计LiveData对象执行以下操作(因为它仅取决于itemsLiveData):

val itemsLiveData: LiveData<List<Items>> = ...
val subtotalLiveData = Transformations.map(itemsLiveData) { 
   items ->
       getSubtotalPrice(items)
}

在总数的情况下,能够做到这样的事情会很棒:

val shipPriceLiveData: LiveData<Int> = ...
val totalLiveData = Transformations.map(itemsLiveData, shipPriceLiveData) { 
   items, price ->
       getSubtotalPrice(items) + price
}

但是,遗憾的是,这是不可能的,因为我们不能在map函数中放置多个参数。任何人都知道实现这个目标的好方法吗?

3 个答案:

答案 0 :(得分:6)

最后我使用MediatorLiveData来达到同样的目标。

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
}

答案 1 :(得分:1)

在这种情况下,您可以使用 switchMap(),因为它会返回LiveData对象,该对象可以是 Transformations.map()

在下面的代码中,我得到两个对象的最终数量之和: onwardSelectQuote returnSelectQuote

finalAmount = Transformations.switchMap(onwardSelectQuote) { data1 ->
            Transformations.map(returnSelectQuote) { data2 -> ViewUtils.formatRupee((data1.finalAmount!!.toFloat() + data2.finalAmount!!.toFloat()).toString())
            }
        }

答案 2 :(得分:0)

我想出了另一种解决方案。

<iframe src="https://docs.google.com/presentation/d/e/guiggeuegtuitgeigiegiegigegeggteuitgeeiuteteg/embed?start=true&loop=false&delayms=15000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>

然后,您可以组合多个来源。

class PairLiveData<A, B>(first: LiveData<A>, second: LiveData<B>) : MediatorLiveData<Pair<A?, B?>>() {
    init {
        addSource(first) { value = it to second.value }
        addSource(second) { value = first.value to it }
    }
}

class TripleLiveData<A, B, C>(first: LiveData<A>, second: LiveData<B>, third: LiveData<C>) : MediatorLiveData<Triple<A?, B?, C?>>() {
    init {
        addSource(first) { value = Triple(it, second.value, third.value) }
        addSource(second) { value = Triple(first.value, it, third.value) }
        addSource(third) { value = Triple(first.value, second.value, it) }
    }
}

fun <A, B> LiveData<A>.combine(other: LiveData<B>): PairLiveData<A, B> {
    return PairLiveData(this, other)
}

fun <A, B, C> LiveData<A>.combine(second: LiveData<B>, third: LiveData<C>): TripleLiveData<A, B, C> {
    return TripleLiveData(this, second, third)
}

如果您想拥有4个或更多的源,则需要创建自己的数据类,因为Kotlin仅具有val totalLiveData = Transformations.map(itemsLiveData.combine(shipPriceLiveData)) { // Do your stuff } Pair

我认为,在Damia的解决方案中没有理由使用Triple