首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有多个参数的LiveData Transformations.map()

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

Stack Overflow用户
提问于 2017-11-30 11:53:45
回答 3查看 9.6K关注 0票数 16

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

代码语言:javascript
复制
val itemsLiveData: LiveData<List<Items>> = ...
val subtotalLiveData = Transformations.map(itemsLiveData) { 
   items ->
       getSubtotalPrice(items)
}

就总数而言,能够这样做是很好的:

代码语言:javascript
复制
val shipPriceLiveData: LiveData<Int> = ...
val totalLiveData = Transformations.map(itemsLiveData, shipPriceLiveData) { 
   items, price ->
       getSubtotalPrice(items) + price
}

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-12-06 12:41:57

更新

基于我之前的回答,我创建了一种通用的方法,我们可以添加任意数量的实时数据。

代码语言:javascript
复制
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)
            }
        }
    }
}

最后,我使用了MediatorLiveData来实现相同的目标。

代码语言:javascript
复制
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
}
票数 12
EN

Stack Overflow用户

发布于 2018-12-05 08:46:37

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

代码语言:javascript
复制
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)
}

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

代码语言:javascript
复制
val totalLiveData = Transformations.map(itemsLiveData.combine(shipPriceLiveData)) {
    // Do your stuff
}

如果您想拥有4个或更多的源,则需要创建自己的数据类,因为Kotlin只有PairTriple

在我看来,没有理由在Damia的解决方案中使用uiThread

票数 13
EN

Stack Overflow用户

发布于 2019-09-06 10:05:52

对于这种情况,您可以使用switchMap(),因为它返回可以是LiveData的LiveData对象

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

代码语言:javascript
复制
finalAmount = Transformations.switchMap(onwardSelectQuote) { data1 ->
            Transformations.map(returnSelectQuote) { data2 -> ViewUtils.formatRupee((data1.finalAmount!!.toFloat() + data2.finalAmount!!.toFloat()).toString())
            }
        }
票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47572913

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档