将多个LiveData值映射到一个

时间:2017-08-16 12:50:51

标签: java android ios objective-c android-livedata

因此,在iOS开发中,我使用ReactiveCocoa并使用该框架,我能够观察多个NSObjects并将它们组合成一个返回值的signal。像这样:

-(RACSignal *)modelIsValidSignal {

    return [RACSignal combineLatest:@[RACObserve(self,username), RACObserve(self,password), RACObserve(self, busyLoggingIn)]
                             reduce:^id(NSString *username, NSString *password, NSNumber *busyLoggingIn) {
                                 return @((username.length > 0) && (password.length > 0 && busyLoggingIn.boolValue == NO));
                             }];
}

因此,这将返回boolean,该值为false或true。只要其中一个对象状态发生变化,就会通知此信号,然后subscriber (Observer)将获得布尔值的当前值。

如何使用LiveData执行类似的操作?最接近这一点的是MediatorLiveData但是,我不知道如何同时观察多个LiveData事件然后减少它,就像上面的例子一样。

3 个答案:

答案 0 :(得分:4)

我做了一些像这样的验证

var firstName: MutableLiveData<String> = MutableLiveData()
var lastName: MutableLiveData<String> = MutableLiveData()

var personalDetailsValid: MediatorLiveData<Boolean> = MediatorLiveData()

personalDetailsValid.addSource(firstName, {
    personalDetailsValid.value = lastName.value?.isNotBlank() == true && it?.isNotBlank() ?: false
})

personalDetailsValid.addSource(lastName, {
    personalDetailsValid.value = firstName.value?.isNotBlank() == true && it?.isNotBlank() ?: false
})

然后我观察通常的方式

viewModel.personalDetailsValid.observe(this, Observer {
        if (it == true) {
            //Do something
        }
    })

我不知道这是否是推荐的使用LiveData和MediatorLiveData的方式,但它对我有用。

答案 1 :(得分:1)

方便且安全的解决方案:

fun <T1, T2, R> combine(
    liveData1: LiveData<T1>,
    liveData2: LiveData<T2>,
    combineFn: (value1: T1?, value2: T2?) -> R
): LiveData<R> = MediatorLiveData<R>().apply {
    addSource(liveData1) {
        value = combineFn(it, liveData2.value)
    }
    addSource(liveData2) {
        value = combineFn(liveData1.value, it)
    }
}

fun <T1, T2, R> Pair<LiveData<T1>, LiveData<T2>>.map(
    combineFn: (value1: T1?, value2: T2?) -> R
) = combine(first, second, combineFn)

使用示例:

val greetLine = combine(nameLiveData, surnameLiveData) { name, surname ->
   "Hello, $name $surname!"
}

// or using map extension function for consistency with LiveData api
val greetLine = (nameLiveData to surnameLiveData).map { name, surname ->
   "Hello, $name $surname!"
}

答案 2 :(得分:0)

我已经为2个(和更多)LiveData值实现了一些util方法。在以RX Observable.combineLatest()方式工作的情况下,这意味着如果观察到的LiveData之一将发出任何新值,它将触发更新的值。我添加了Function2作为“合并器”函数(在我的情况下,我可以轻松使用RX.BiFunction,但是LiveData可以发出null值)。

合并两个LiveData中的值的示例。

object LiveDataUtils {

    fun <T1, T2, R> combineLatest(source1: LiveData<T1>,
                                  source2: LiveData<T2>,
                                  combiner: Function2<T1, T2, R>): LiveData<R> {
        val mediator = MediatorLiveData<R>()

        val combinerFunction = {
            val source1Value = source1.value
            val source2Value = source2.value
            mediator.value = combiner.apply(source1Value, source2Value)
        }

        mediator.addSource(source1) { combinerFunction() }
        mediator.addSource(source2) { combinerFunction() }
        return mediator
    }

}

interface Function2<T1, T2, R> {
    fun apply(t1: T1?, t2: T2?): R
}