How To Combine Two Live Data One After The Other?
Solution 1:
You can use my helper method:
val profile = MutableLiveData<ProfileData>()
val user = MutableLiveData<CurrentUser>()
val title = profile.combineWith(user) { profile, user ->
"${profile.job}${user.name}"
}
fun<T, K, R> LiveData<T>.combineWith(
liveData: LiveData<K>,
block: (T?, K?) -> R
): LiveData<R> {
val result = MediatorLiveData<R>()
result.addSource(this) {
result.value = block(this.value, liveData.value)
}
result.addSource(liveData) {
result.value = block(this.value, liveData.value)
}
return result
}
Solution 2:
With the help of MediatorLiveData, you can combine results from multiple sources. Here an example of how would I combine two sources:
classCombinedLiveData<T, K, S>(source1: LiveData<T>, source2: LiveData<K>, privateval combine: (data1: T?, data2: K?) -> S) : MediatorLiveData<S>() {
privatevar data1: T? = nullprivatevar data2: K? = nullinit {
super.addSource(source1) {
data1 = it
value = combine(data1, data2)
}
super.addSource(source2) {
data2 = it
value = combine(data1, data2)
}
}
overridefun<S : Any?>addSource(source: LiveData<S>, onChanged: Observer<inS>) {
throw UnsupportedOperationException()
}
overridefun<T : Any?>removeSource(toRemove: LiveData<T>) {
throw UnsupportedOperationException()
}
}
here is the gist for above, in case it is updated on the future: https://gist.github.com/guness/0a96d80bc1fb969fa70a5448aa34c215
Solution 3:
Jose Alcérreca has probably the best answer for this:
funblogpostBoilerplateExample(newUser: String): LiveData<UserDataResult> {
val liveData1 = userOnlineDataSource.getOnlineTime(newUser)
val liveData2 = userCheckinsDataSource.getCheckins(newUser)
val result = MediatorLiveData<UserDataResult>()
result.addSource(liveData1) { value ->
result.value = combineLatestData(liveData1, liveData2)
}
result.addSource(liveData2) { value ->
result.value = combineLatestData(liveData1, liveData2)
}
return result
}
Solution 4:
You can define a method that would combine multiple LiveDatas using a MediatorLiveData, then expose this combined result as a tuple.
publicclassCombinedLiveData2<A, B> extendsMediatorLiveData<Pair<A, B>> {
private A a;
private B b;
publicCombinedLiveData2(LiveData<A> ld1, LiveData<B> ld2) {
setValue(Pair.create(a, b));
addSource(ld1, (a) -> {
if(a != null) {
this.a = a;
}
setValue(Pair.create(a, b));
});
addSource(ld2, (b) -> {
if(b != null) {
this.b = b;
}
setValue(Pair.create(a, b));
});
}
}
If you need more values, then you can create a CombinedLiveData3<A,B,C>
and expose a Triple<A,B,C>
instead of the Pair, etc. Just like in https://stackoverflow.com/a/54292960/2413303 .
EDIT: hey look, I even made a library for you that does that from 2 arity up to 16: https://github.com/Zhuinden/livedata-combinetuple-kt
Solution 5:
I did an approach based on @guness answer. I found that being limited to two LiveData
s was not good. What if we want to use 3? We need to create different classes for every case. So, I created a class that handles an unlimited amount of LiveData
s.
/**
* CombinedLiveData is a helper class to combine results from multiple LiveData sources.
* @param liveDatas Variable number of LiveData arguments.
* @param combine Function reference that will be used to combine all LiveData data results.
* @param R The type of data returned after combining all LiveData data.
* Usage:
* CombinedLiveData<SomeType>(
* getLiveData1(),
* getLiveData2(),
* ... ,
* getLiveDataN()
* ) { datas: List<Any?> ->
* // Use datas[0], datas[1], ..., datas[N] to return a SomeType value
* }
*/classCombinedLiveData<R>(vararg liveDatas: LiveData<*>,
privateval combine: (datas: List<Any?>) -> R) : MediatorLiveData<R>() {
privateval datas: MutableList<Any?> = MutableList(liveDatas.size) { null }
init {
for(i in liveDatas.indices){
super.addSource(liveDatas[i]) {
datas[i] = it
value = combine(datas)
}
}
}
}
Post a Comment for "How To Combine Two Live Data One After The Other?"