Как объединить 3 или более источников LiveData разных дженериков? - PullRequest
0 голосов
/ 27 апреля 2020

Я пытаюсь объединить 3 или более LiveData в качестве источников, где каждый LiveData имеет общий тип c, отличный от других. Для этого я намерен использовать vararg , который получает каждый LiveData со своим соответствующим типом.

Я уже решил это, но с «жестким кодом» для 3 источников данных с решением, очень похожим на этот ответ , но это не масштабируется.

Цель использования заключается в следующем (не компилируется):

    fun getSourceR(): MutableLiveData<Object_R>() {}
    fun getSourceS(): MutableLiveData<Object_S>() {}
    fun getSourceU(): MutableLiveData<Object_U>() {}

    MergeLiveDataTest(getSourceR(), getSourceS(), getSourceU()) {
        sources ->
            Log.d("MergeLiveData", sources[0].value.methodOf_R)
            Log.d("MergeLiveData", sources[1].value.methodOf_S)
            Log.d("MergeLiveData", sources[2].value.methodOf_U)
    }

Проблема: Я не могу получить доступ к методам объекта типа источника.


У меня есть следующая реализация:

Я пытаюсь сделать make каждая итерация l oop X будет R, S или U.

class MergeLiveDataTest<T, X>(
        vararg sources: LiveData<X>,
        private val onChanged: (newData: MutableList<LiveData<X>>) -> T
) : MediatorLiveData<T>() {
    private lateinit var _sources: MutableList<LiveData<X>>
    init {
        for (i in sources.indices) {
            super.addSource(sources[i]) {
                _sources.add(i, sources[i])
                value = onChanged(_sources)
            }
        }
    }
}

Есть предложения? Спасибо

Источник

1 Ответ

1 голос
/ 27 апреля 2020

Я уже решил эту проблему, но с «жестким кодом» для 3 источников данных, решение, очень похожее на решение, приведенное в этом ответе, но это не масштабируется.

Конечно, убежище Вы видели РЕДАКТИРОВАТЬ? ;)

Вы можете использовать библиотеку https://github.com/Zhuinden/livedata-combinetuple-kt, которая делает то же самое.

Теперь только для ссылок ответы не очень хорошая вещь, поэтому я объясню, что они делают.

Сначала у меня есть кортежи из 4-16 аритов (потому что Kotlin уже имеет Pair и Triple) в tuples-kt

Они выглядят так:

data class Tuple4<A, B, C, D>(
    val first: A,
    val second: B,
    val third: C,
    val fourth: D
) : Serializable {
    override fun toString(): String {
        return "Tuple4[$first, $second, $third, $fourth]"
    }
}

data class Tuple5<A, B, C, D, E>(
    val first: A,
    val second: B,
    val third: C,
    val fourth: D,
    val fifth: E
) : Serializable {
    override fun toString(): String {
        return "Tuple5[$first, $second, $third, $fourth, $fifth]"
    }
}

Затем в LiveData-CombineTuple-KT есть код, подобный этому:

fun <T1, T2, T3, T4> combineTuple(f1: LiveData<T1>, f2: LiveData<T2>, f3: LiveData<T3>, f4: LiveData<T4>): LiveData<Tuple4<T1?, T2?, T3?, T4?>> = MediatorLiveData<Tuple4<T1?, T2?, T3?, T4?>>().also { mediator ->
    mediator.value = Tuple4(f1.value, f2.value, f3.value, f4.value)

    mediator.addSource(f1) { t1: T1? ->
        val (_, t2, t3, t4) = mediator.value!!
        mediator.value = Tuple4(t1, t2, t3, t4)
    }

    mediator.addSource(f2) { t2: T2? ->
        val (t1, _, t3, t4) = mediator.value!!
        mediator.value = Tuple4(t1, t2, t3, t4)
    }

    mediator.addSource(f3) { t3: T3? ->
        val (t1, t2, _, t4) = mediator.value!!
        mediator.value = Tuple4(t1, t2, t3, t4)
    }

    mediator.addSource(f4) { t4: T4? ->
        val (t1, t2, t3, _) = mediator.value!!
        mediator.value = Tuple4(t1, t2, t3, t4)
    }
}

fun <T1, T2, T3, T4, T5> combineTuple(f1: LiveData<T1>, f2: LiveData<T2>, f3: LiveData<T3>, f4: LiveData<T4>, f5: LiveData<T5>): LiveData<Tuple5<T1?, T2?, T3?, T4?, T5?>> = MediatorLiveData<Tuple5<T1?, T2?, T3?, T4?, T5?>>().also { mediator ->
    mediator.value = Tuple5(f1.value, f2.value, f3.value, f4.value, f5.value)

    mediator.addSource(f1) { t1: T1? ->
        val (_, t2, t3, t4, t5) = mediator.value!!
        mediator.value = Tuple5(t1, t2, t3, t4, t5)
    }

    mediator.addSource(f2) { t2: T2? ->
        val (t1, _, t3, t4, t5) = mediator.value!!
        mediator.value = Tuple5(t1, t2, t3, t4, t5)
    }

    mediator.addSource(f3) { t3: T3? ->
        val (t1, t2, _, t4, t5) = mediator.value!!
        mediator.value = Tuple5(t1, t2, t3, t4, t5)
    }

    mediator.addSource(f4) { t4: T4? ->
        val (t1, t2, t3, _, t5) = mediator.value!!
        mediator.value = Tuple5(t1, t2, t3, t4, t5)
    }

    mediator.addSource(f5) { t5: T5? ->
        val (t1, t2, t3, t4, _) = mediator.value!!
        mediator.value = Tuple5(t1, t2, t3, t4, t5)
    }
}

Записывается от 3 до 16. Несмотря на то, что это библиотека Kotlin, предполагается, что в вашем проекте есть Kotlin -stdlib для Pair и Triple.

В любом случае, я бы предположил, что возможности объединения 16 LiveData в кортеж должно быть достаточно для большинства сценариев ios.

Если Kotlin не разрешен, то я уверен, что соответствующие Kotlin logi c можно перевести на Java, но это было бы намного более многословно, поэтому я никогда этого не делал.

В Kotlin теперь вы можете легко сделать это:

val liveData = combineTuple(liveData1, liveData2, liveData3).map { (value1, value2, value3) ->
    // do something with nullable values
}

liveData.observe(this) { mappedValue ->
    // do something with mapped value
}


Ваш пример изменится следующим образом

fun getSourceR(): MutableLiveData<Object_R>() {}
fun getSourceS(): MutableLiveData<Object_S>() {}
fun getSourceU(): MutableLiveData<Object_U>() {}

combineTuple(getSourceR(), getSourceS(), getSourceU()).map { (r, s, u) ->
    sources ->
        Log.d("MergeLiveData", r?.methodOf_R)
        Log.d("MergeLiveData", s?.methodOf_S)
        Log.d("MergeLiveData", u?.methodOf_U)
}

Советую попробовать.

...