猿问

如何使用LiveData实现zip功能

我正在使用两个 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 的两个值


慕妹3242003
浏览 160回答 5
5回答

呼唤远方

你需要的是所谓的zip功能:fun <A, B> zip(first: LiveData<A>, second: LiveData<B>): LiveData<Pair<A, B>> {&nbsp; &nbsp; val mediatorLiveData = MediatorLiveData<Pair<A, B>>()&nbsp; &nbsp; var isFirstEmitted = false&nbsp; &nbsp; var isSecondEmitted = false&nbsp; &nbsp; var firstValue: A? = null&nbsp; &nbsp; var secondValue: B? = null&nbsp; &nbsp; mediatorLiveData.addSource(first) {&nbsp; &nbsp; &nbsp; &nbsp; isFirstEmitted = true&nbsp; &nbsp; &nbsp; &nbsp; firstValue = it&nbsp; &nbsp; &nbsp; &nbsp; if (isSecondEmitted) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mediatorLiveData.value = Pair(firstValue!!, secondValue!!)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isFirstEmitted = false&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isSecondEmitted = false&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; mediatorLiveData.addSource(second) {&nbsp; &nbsp; &nbsp; &nbsp; isSecondEmitted = true&nbsp; &nbsp; &nbsp; &nbsp; secondValue = it&nbsp; &nbsp; &nbsp; &nbsp; if (isFirstEmitted) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mediatorLiveData.value = Pair(firstValue!!, secondValue!!)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isFirstEmitted = false&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isSecondEmitted = false&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return mediatorLiveData}现在,您可以调用zip(firstLiveData,secondLiveData)并观察它。

守着星空守着你

这是一个更通用的版本,它允许您观察多个LiveData.fun zipLiveData(vararg liveItems: LiveData<*>): LiveData<ArrayList<Any>> {&nbsp; &nbsp; //MediatorLiveData used to merge multiple LiveDatas&nbsp; &nbsp; return MediatorLiveData<ArrayList<Any>>().apply {&nbsp; &nbsp; &nbsp; &nbsp; val zippedObjects = ArrayList<Any>()&nbsp; &nbsp; &nbsp; &nbsp; liveItems.forEach {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Add each LiveData as a source for the MediatorLiveData&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addSource(it) { item ->&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Add value to list&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; item?.let { it1 -> zippedObjects.add(it1) }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (zippedObjects.size == liveItems.size) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //If all the LiveData items has returned a value, save that value in MediatorLiveData.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = zippedObjects&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Clear the list for next time&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zippedObjects.clear()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}上面的函数不会将null值添加到列表中,假设您null也想添加值,您需要按照以下几行做一些事情,fun zipLiveData(vararg liveItems: LiveData<*>): LiveData<ArrayList<Any?>> {&nbsp; &nbsp; return MediatorLiveData<ArrayList<Any?>>().apply {&nbsp; &nbsp; &nbsp; &nbsp; val zippedObjects = ArrayList<Any?>()&nbsp; &nbsp; &nbsp; &nbsp; liveItems.forEach {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addSource(it) { item ->&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zippedObjects.add(item)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (zippedObjects.size == liveItems.size) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = zippedObjects&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zippedObjects.clear()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}更新- 我刚刚意识到上述方法不保留项目的“顺序” LiveData(例如,如果第二个LiveData在第一个之前发布了一个值,您将获得值[secondLiveDataValue, firstLiveDataValue]而不是预期值[firstLiveDataValue, secondLiveDataValue])。如果您希望保留项目值的“顺序”,则可以改用以下两个函数之一LiveData。//If you know the LiveDatas won't get null valuesfun zipLiveData(vararg liveItems: LiveData<*>): LiveData<ArrayList<Any?>> {&nbsp; &nbsp; return MediatorLiveData<ArrayList<Any?>>().apply {&nbsp; &nbsp; &nbsp; &nbsp; var zippedObjects = arrayOfNulls<Any>(liveItems.size)&nbsp; &nbsp; &nbsp; &nbsp; liveItems.forEachIndexed { index, liveData ->&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addSource(liveData) { item ->&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zippedObjects[index] = item&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!zippedObjects.contains(null)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = zippedObjects.toCollection(ArrayList())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zippedObjects = arrayOfNulls(liveItems.size)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}//Incase your LiveDatas might have null valuesfun zipLiveDataWithNull(vararg liveItems: LiveData<*>): LiveData<ArrayList<Any?>> {&nbsp; &nbsp; return MediatorLiveData<ArrayList<Any?>>().apply {&nbsp; &nbsp; &nbsp; &nbsp; val zippedObjects = arrayOfNulls<Any>(liveItems.size)&nbsp; &nbsp; &nbsp; &nbsp; val zippedObjectsFlag = BooleanArray(liveItems.size)&nbsp; &nbsp; &nbsp; &nbsp; liveItems.forEachIndexed { index, liveData ->&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addSource(liveData) { item ->&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zippedObjects[index] = item&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zippedObjectsFlag[index] = true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!zippedObjectsFlag.contains(false)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = zippedObjects.toCollection(ArrayList())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i in 0 until liveItems.size) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zippedObjectsFlag[i] = false&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}

牧羊人nacy

这个扩展功能对我有用fun <A, B> LiveData<A>.zipWith(stream: LiveData<B>): LiveData<Pair<A, B>> {&nbsp;val result = MediatorLiveData<Pair<A, B>>()&nbsp; result.addSource(this) { a ->&nbsp; &nbsp; if (a != null && stream.value != null) {&nbsp; &nbsp; &nbsp; &nbsp; result.value = Pair(a, stream.value!!)&nbsp; &nbsp; }&nbsp; }&nbsp;result.addSource(stream) { b ->&nbsp; &nbsp; if (b != null && this.value != null) {&nbsp; &nbsp; &nbsp; &nbsp; result.value = Pair(this.value!!, b)&nbsp; &nbsp; }&nbsp;}&nbsp;return result}

蛊毒传说

我的解决方案有点受到 rxjava zip 运算符的启发,inline fun <reified I1, I2, O> biZip(inputLiveData1: LiveData<I1>, inputLiveData2: LiveData<I2>, crossinline tranform: (data1: I1, data2: I2) -> O): LiveData<O> {&nbsp; &nbsp; var input1: I1? = null&nbsp; &nbsp; var input2: I2? = null&nbsp; &nbsp; val mediatorLiveData = MediatorLiveData<O>()&nbsp; &nbsp; mediatorLiveData.addSource(inputLiveData1) {&nbsp; &nbsp; &nbsp; &nbsp; input1 = it&nbsp; &nbsp; &nbsp; &nbsp; if (input1 != null && input2 != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mediatorLiveData.value = tranform.invoke(input1!!, input2!!)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; mediatorLiveData.addSource(inputLiveData2) {&nbsp; &nbsp; &nbsp; &nbsp; input2 = it&nbsp; &nbsp; &nbsp; &nbsp; if (input1 != null && input2 != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mediatorLiveData.value = tranform.invoke(input1!!, input2!!)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return mediatorLiveData}现在你可以像这样使用它val liveDataString = MutableLiveData<String>()val liveDataInt = MutableLiveData<Int>()val liveDataofTest = biZip<String, Int, Test>(liveDataString, liveDataInt) { data1:String, data2:Int ->&nbsp; &nbsp; &nbsp; return@biZip Test(data1, data2)}测试 pojo 就像data class Test(val name:String,value:Int)

沧海一幻觉

您可以像扩展功能一样直接使用它fun <A, B, C> LiveData<A>.zip(stream: LiveData<B>, func: (source1: A?, source2: B?) -> C): LiveData<C> {&nbsp; &nbsp; &nbsp; &nbsp; val result = MediatorLiveData<C>()&nbsp; &nbsp; &nbsp; &nbsp; result.addSource(this) { a ->&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result.setValue(func.invoke(a,stream.value))&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; result.addSource(stream) { b ->&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result.setValue(func.invoke(this.value, b))&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return result}
随时随地看视频慕课网APP

相关分类

Java
我要回答