13

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

-(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为假或真的。只要其中一个对象的状态发生变化,就会通知该信号,subscriber (Observer)然后将获得该布尔值的当前值。

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

4

3 回答 3

17

我已经做了一些这样的验证

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 的推荐方式,但它对我有用。

于 2018-03-10T07:42:21.103 回答
1

我已经为 2 个(以及更多) LiveData 值实现了一些实用方法。以 RXObservable.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
}
于 2020-02-06T11:14:39.413 回答
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!"
}
于 2021-04-28T14:27:32.577 回答