亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何使用LiveData實現zip功能

如何使用LiveData實現zip功能

慕妹3242003 2023-04-26 15:17:13
我正在使用兩個 LiveDatas 從我的服務器獲取數據,并且想在兩個 LiveData 完成后得到結果?LiveData live1 = ...;LiveData live2 = ...;MutableLiveData live3 = ...;live1.observe(this, value -> {    live3.postValue(value);});live2.observe(this, value -> {   live3.postValue(value);});live3.observe(this,  value -> {// TODO: Get both values from live1, live2}我期望 live1 和 live2 的兩個值
查看完整描述

5 回答

?
呼喚遠方

TA貢獻1856條經驗 獲得超11個贊

你需要的是所謂的zip功能:


fun <A, B> zip(first: LiveData<A>, second: LiveData<B>): LiveData<Pair<A, B>> {

    val mediatorLiveData = MediatorLiveData<Pair<A, B>>()


    var isFirstEmitted = false

    var isSecondEmitted = false

    var firstValue: A? = null

    var secondValue: B? = null


    mediatorLiveData.addSource(first) {

        isFirstEmitted = true

        firstValue = it

        if (isSecondEmitted) {

            mediatorLiveData.value = Pair(firstValue!!, secondValue!!)

            isFirstEmitted = false

            isSecondEmitted = false

        }

    }

    mediatorLiveData.addSource(second) {

        isSecondEmitted = true

        secondValue = it

        if (isFirstEmitted) {

            mediatorLiveData.value = Pair(firstValue!!, secondValue!!)

            isFirstEmitted = false

            isSecondEmitted = false

        }

    }


    return mediatorLiveData

}



現在,您可以調用zip(firstLiveData,secondLiveData)并觀察它。


查看完整回答
反對 回復 2023-04-26
?
守著星空守著你

TA貢獻1799條經驗 獲得超8個贊

這是一個更通用的版本,它允許您觀察多個LiveData.


fun zipLiveData(vararg liveItems: LiveData<*>): LiveData<ArrayList<Any>> {

    //MediatorLiveData used to merge multiple LiveDatas

    return MediatorLiveData<ArrayList<Any>>().apply {

        val zippedObjects = ArrayList<Any>()

        liveItems.forEach {

            //Add each LiveData as a source for the MediatorLiveData

            addSource(it) { item ->

                //Add value to list

                item?.let { it1 -> zippedObjects.add(it1) }

                if (zippedObjects.size == liveItems.size) {

                    //If all the LiveData items has returned a value, save that value in MediatorLiveData.

                    value = zippedObjects

                    //Clear the list for next time

                    zippedObjects.clear()

                }

            }

        }

    }

}

上面的函數不會將null值添加到列表中,假設您null也想添加值,您需要按照以下幾行做一些事情,


fun zipLiveData(vararg liveItems: LiveData<*>): LiveData<ArrayList<Any?>> {

    return MediatorLiveData<ArrayList<Any?>>().apply {

        val zippedObjects = ArrayList<Any?>()

        liveItems.forEach {

            addSource(it) { item ->

                zippedObjects.add(item)

                if (zippedObjects.size == liveItems.size) {

                    value = zippedObjects

                    zippedObjects.clear()

                }

            }

        }

    }

}

更新- 我剛剛意識到上述方法不保留項目的“順序” LiveData(例如,如果第二個LiveData在第一個之前發布了一個值,您將獲得值[secondLiveDataValue, firstLiveDataValue]而不是預期值[firstLiveDataValue, secondLiveDataValue])。如果您希望保留項目值的“順序”,則可以改用以下兩個函數之一LiveData。


//If you know the LiveDatas won't get null values

fun zipLiveData(vararg liveItems: LiveData<*>): LiveData<ArrayList<Any?>> {

    return MediatorLiveData<ArrayList<Any?>>().apply {

        var zippedObjects = arrayOfNulls<Any>(liveItems.size)

        liveItems.forEachIndexed { index, liveData ->

            addSource(liveData) { item ->

                zippedObjects[index] = item

                if (!zippedObjects.contains(null)) {

                    value = zippedObjects.toCollection(ArrayList())

                    zippedObjects = arrayOfNulls(liveItems.size)

                }

            }

        }

    }

}


//Incase your LiveDatas might have null values

fun zipLiveDataWithNull(vararg liveItems: LiveData<*>): LiveData<ArrayList<Any?>> {

    return MediatorLiveData<ArrayList<Any?>>().apply {

        val zippedObjects = arrayOfNulls<Any>(liveItems.size)

        val zippedObjectsFlag = BooleanArray(liveItems.size)

        liveItems.forEachIndexed { index, liveData ->

            addSource(liveData) { item ->

                zippedObjects[index] = item

                zippedObjectsFlag[index] = true

                if (!zippedObjectsFlag.contains(false)) {

                    value = zippedObjects.toCollection(ArrayList())

                    for(i in 0 until liveItems.size) {

                        zippedObjectsFlag[i] = false

                    }

                }

            }

        }

    }

}


查看完整回答
反對 回復 2023-04-26
?
牧羊人nacy

TA貢獻1862條經驗 獲得超7個贊

這個擴展功能對我有用


fun <A, B> LiveData<A>.zipWith(stream: LiveData<B>): LiveData<Pair<A, B>> {

 val result = MediatorLiveData<Pair<A, B>>()

  result.addSource(this) { a ->

    if (a != null && stream.value != null) {

        result.value = Pair(a, stream.value!!)

    }

  }

 result.addSource(stream) { b ->

    if (b != null && this.value != null) {

        result.value = Pair(this.value!!, b)

    }

 }

 return result

}


查看完整回答
反對 回復 2023-04-26
?
蠱毒傳說

TA貢獻1895條經驗 獲得超3個贊

我的解決方案有點受到 rxjava zip 運算符的啟發,


inline fun <reified I1, I2, O> biZip(inputLiveData1: LiveData<I1>, inputLiveData2: LiveData<I2>, crossinline tranform: (data1: I1, data2: I2) -> O): LiveData<O> {


    var input1: I1? = null

    var input2: I2? = null

    val mediatorLiveData = MediatorLiveData<O>()

    mediatorLiveData.addSource(inputLiveData1) {

        input1 = it

        if (input1 != null && input2 != null) {

            mediatorLiveData.value = tranform.invoke(input1!!, input2!!)

        }

    }

    mediatorLiveData.addSource(inputLiveData2) {

        input2 = it

        if (input1 != null && input2 != null) {

            mediatorLiveData.value = tranform.invoke(input1!!, input2!!)

        }

    }


    return mediatorLiveData

}

現在你可以像這樣使用它


val liveDataString = MutableLiveData<String>()

val liveDataInt = MutableLiveData<Int>()


val liveDataofTest = biZip<String, Int, Test>(liveDataString, liveDataInt) { data1:String, data2:Int ->

      return@biZip Test(data1, data2)

}


測試 pojo 就像


data class Test(val name:String,value:Int)


查看完整回答
反對 回復 2023-04-26
?
滄海一幻覺

TA貢獻1824條經驗 獲得超5個贊

您可以像擴展功能一樣直接使用它


fun <A, B, C> LiveData<A>.zip(stream: LiveData<B>, func: (source1: A?, source2: B?) -> C): LiveData<C> {

        val result = MediatorLiveData<C>()

        result.addSource(this) { a -> 

            result.setValue(func.invoke(a,stream.value))

        }

        result.addSource(stream) { b -> 

            result.setValue(func.invoke(this.value, b)) 

        }

        return result

}


查看完整回答
反對 回復 2023-04-26
  • 5 回答
  • 0 關注
  • 211 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號