Home » Android » java – Map multiple LiveData values into one

java – Map multiple LiveData values into one

Posted by: admin June 15, 2020 Leave a comment

Questions:

So, in iOS development, I use ReactiveCocoa and with that framework I am able to observe multiple NSObjects and combine them into a signal that returns a a value. Something like this:

-(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));
                             }];
}

So, this will return a boolean that is either false or true. As soon as one of the objects state changes, this signal would be notified and the subscriber (Observer) would then get that current value of the boolean.

How do I do something similar to this, using LiveData? the closest thing to doing this, is MediatorLiveData but, I don’t see how I can observe multiple LiveData events at the same time and then reduce it, like in the above example.

How to&Answers:

I have made some validation like this

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
})

Then I observe the usual way

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

I don’t know if this is the recommended way of using LiveData and MediatorLiveData but it works for me.

Answer:

I’ve implemented some util methods for 2 (and more) LiveData values. In works in a RX Observable.combineLatest() manner, meaning that it fires updated value if one of the observed LiveData will emit any new value. I’ve added Function2 as a “combiner” function (in my case I could easily use RX.BiFunction, but LiveData can emit null values).

Example of combining values from two 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
}