Is it possible to make one LiveData of two LiveDatas?

前端 未结 3 1911
醉梦人生
醉梦人生 2020-12-03 18:59

I have two DAOs, two Repositories and two POJOs. There is some way to create one Livedata of two? I need it to make single list for Recyclerview. POJOs are similar objects.<

相关标签:
3条回答
  • 2020-12-03 19:11

    Instead of having a class to add 2 live datas, another class to add 3 live datas, etc. We can use a more abstract way where we can add as many live datas as we want.

    import androidx.lifecycle.LiveData
    import androidx.lifecycle.MediatorLiveData
    
    /**
     * 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.
     * @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-03 19:15

    I assume you want to combine them, yes? You'll need a MediatorLiveData, but the guy saying you now need Object is wrong. What you need is a MediatorLiveData<Pair<List<Expense>, List<Income>>>.

    public class CombinedLiveData extends MediatorLiveData<Pair<List<Expense>, List<Income>>> {
        private List<Expense> expenses = Collections.emptyList();
        private List<Income> incomes = Collections.emptyList();
    
        public CombinedLiveData(LiveData<List<Expense>> ld1, LiveData<List<Income>> ld2) {
            setValue(Pair.create(expenses, incomes));
    
            addSource(ld1, expenses -> { 
                 if(expenses != null) {
                    this.expenses = expenses;
                 } 
                 setValue(Pair.create(expenses, incomes)); 
            });
    
            addSource(ld2, incomes -> { 
                if(incomes != null) {
                    this.incomes = incomes;
                } 
                setValue(Pair.create(expenses, incomes));
            });
        }
    }
    

    You could potentially make this generic and it'd be the implementation of combineLatest for two LiveData using tuples of 2-arity (Pair).

    EDIT: like this:

    public class CombinedLiveData2<A, B> extends MediatorLiveData<Pair<A, B>> {
        private A a;
        private B b;
    
        public CombinedLiveData2(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));
            });
        }
    }
    

    Beware that I lost the ability to set Collections.emptyList() as initial values of A and B with this scenario, and you WILL need to check for nulls when you access the data inside the pair.

    EDIT: You can use the library https://github.com/Zhuinden/livedata-combinetuple-kt which does the same thing.

    0 讨论(0)
  • 2020-12-03 19:23

    Let's say you want to merge LiveData<List<Expense>> & LiveData<List<Income>> then, you'll need to take MediatorLiveData<Object> (why? because, both of your live data are of different types).

    So, use code like below :

    LiveData liveData1 = getAllExpensesByDay();
    LiveData liveData2 = getAllIncomesByDay();
    MediatorLiveData liveDataMerger = new MediatorLiveData<Object>();
    liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
    liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
    

    If you need to use specific data from MediatorLiveData then use Transformations on that.

    Check out more here

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