How to combine two live data one after the other?

前端 未结 7 1739
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-13 05:13

I have next use case: User comes to registration form, enters name, email and password and clicks on register button. After that system needs to check if email is taken or n

相关标签:
7条回答
  • 2020-12-13 05:32

    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
    }
    
    0 讨论(0)
  • 2020-12-13 05:40

    I did an approach based on @guness answer. I found that being limited to two LiveDatas 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 LiveDatas.

    /**
      * 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
      * }
      */
     class CombinedLiveData<R>(vararg liveDatas: LiveData<*>,
                               private val combine: (datas: List<Any?>) -> R) : MediatorLiveData<R>() {
    
          private val datas: MutableList<Any?> = MutableList(liveDatas.size) { null }
    
          init {
             for(i in liveDatas.indices){
                 super.addSource(liveDatas[i]) {
                     datas[i] = it
                     value = combine(datas)
                 }
             }
         }
     }
    
    0 讨论(0)
  • 2020-12-13 05:41

    if you want both value not null

    fun <T, V, R> LiveData<T>.combineWithNotNull(
            liveData: LiveData<V>,
            block: (T, V) -> R
    ): LiveData<R> {
        val result = MediatorLiveData<R>()
        result.addSource(this) {
            this.value?.let { first ->
                liveData.value?.let { second ->
                    result.value = block(first, second)
                }
            }
        }
        result.addSource(liveData) {
            this.value?.let { first ->
                liveData.value?.let { second ->
                    result.value = block(first, second)
                }
            }
        }
    
        return result
    }
    
    0 讨论(0)
  • 2020-12-13 05:45
    LiveData liveData1 = ...;
     LiveData liveData2 = ...;
    
     MediatorLiveData liveDataMerger = new MediatorLiveData<>();
     liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
     liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
    
    0 讨论(0)
  • 2020-12-13 05:47

    Jose Alcérreca has probably the best answer for this:

    fun blogpostBoilerplateExample(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
    }
    
    0 讨论(0)
  • 2020-12-13 05:48

    With the help of MediatorLiveData, you can combine results from multiple sources. Here an example of how would I combine two sources:

    class CombinedLiveData<T, K, S>(source1: LiveData<T>, source2: LiveData<K>, private val combine: (data1: T?, data2: K?) -> S) : MediatorLiveData<S>() {
    
    private var data1: T? = null
    private var data2: K? = null
    
    init {
        super.addSource(source1) {
            data1 = it
            value = combine(data1, data2)
        }
        super.addSource(source2) {
            data2 = it
            value = combine(data1, data2)
        }
    }
    
    override fun <T : Any?> addSource(source: LiveData<T>, onChanged: Observer<T>) {
        throw UnsupportedOperationException()
    }
    
    override fun <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

    0 讨论(0)
提交回复
热议问题