Несовместимые типы с LiveData ребенка как LiveData родителя - PullRequest
0 голосов
/ 06 ноября 2018

Я хочу использовать MutableLiveData для наблюдения некоторых данных из ViewModel. Проблема в том, что я использую дочерний и родительский класс, и есть некоторая несовместимость с LiveData. Пример того, что я хочу сделать в Котлине:

import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.ViewModel

class Test : ViewModel() {

    abstract class Parent(protected var id: Int)

    class ChildFirst(id: Int) : Parent(id)

    class ChildSecond(id: Int) : Parent(id)

    var childFirst : MutableLiveData<ChildFirst> = MutableLiveData<ChildFirst>()

    var childSecond : MutableLiveData<ChildSecond> = MutableLiveData<ChildSecond>()

    var shouldManageFirstChild = true

    fun returnCorrectChild(): MutableLiveData<Parent> {
        if (shouldManageFirstChild) {
            return childFirst //won't compile in Android Studio (Type mismatch)
        } else {
            return childSecond as MutableLiveData<Parent> //compile and work with a warning in AndroidStudio (Unchecked cast)
        }
    }
}

А вот в Java:

import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;

public class Test extends ViewModel {
    class Parent {
        protected int mId;

        Parent(int id) {
            mId = id;
        }
    }

    class ChildFirst extends Parent {
        ChildFirst(int id) {
            super(id);
        }
    }

    class ChildSecond extends Parent {
        ChildSecond(int id) {
            super(id);
        }
    }

    MutableLiveData<ChildFirst> childFirst = new MutableLiveData <ChildFirst>();

    MutableLiveData<ChildSecond> childSecond = new MutableLiveData <ChildSecond>();
    boolean shouldManageFirstChild = true;

    MutableLiveData<Parent> returnCorrectChild(){
        if (shouldManageFirstChild) {
            return childFirst; //won't compile in Android Studio (Incompatible type)
        } else {
            return (MutableLiveData<Parent>) childSecond;   //won't compile in Android Studio (Inconvertible cast)
        }
    }
}

Как видите, проблема в том, что компилятор не считает тип одинаковым для MutableLiveData и MutableLiveData .

В Kotlin я могу разыграть LiveData ребенка как родителя. Даже если есть предупреждение, код запускается как задумано: я могу наблюдать MutableLiveData .

Хуже того, в Java невозможно скомпилировать даже с использованием приведения.

Так вот мой вопрос:

  • Почему я не могу использовать LiveData ребенка в качестве LiveData родителя? Это то, что предназначено LiveData?

  • Являются ли они какими-то возможными последствиями использования этого слова с kotlin 'как'?

Ответы [ 2 ]

0 голосов
/ 06 ноября 2018

Почему я не могу использовать LiveData ребенка в качестве LiveData родителя? Это что-то предназначенное для LiveData?

В java ответ довольно прост: универсальные типы в Java инвариантны, что означает, что List<String> не является подтипом List<Object> (цитируется по kotlin docs здесь )

Являются ли они какими-то возможными последствиями использования этого слова с kotlin 'as'

Kotlin просто делает предупреждение во время компиляции, но во время выполнения происходит то, что ваша проверка только против не-обобщенной части. Вот почему, я думаю (и если кто-то знает лучше меня, пожалуйста, объясните! Я сумасшедший об этом), вы можете сделать это в Kotlin.

Для лучшего объяснения того, что происходит в kotlin (а ​​также в Java) при использовании типа дженериков, я рекомендую вам прочитать полные документы kotlin о дженериках здесь Есть даже много статей о кастинге дженериков Java, таких как this one

EDIT: Способ решения вашей проблемы может быть следующим: объявлять единственные данные в реальном времени и обращаться с детьми простым образом, как это:

val liveParent = MutableLiveData<Parent>()
val childFirst = ChildFirst()
val childSecond = ChildSecond()

и затем верните правильного потомка в liveParent при вызове returnCorrectChild()

fun returnCorrectChild() {
    if (shouldManageFirstChild) {
        liveParent.value = firstChild
    } else {
        liveParent.value = secondChild
    }
}
0 голосов
/ 06 ноября 2018

Вы можете реорганизовать функцию returnCorrectChild (), чтобы она возвращала универсальный тип, а затем проверить, является ли возвращаемый тип экземпляром ChildFirst или ChildSecond вне вашего класса ViewModel

Что-то вроде:

  fun returnCorrectChild(): MutableLiveData<*> {
        if (shouldManageFirstChild) {
            return childFirst
        } else {
            return childSecond
        }
    }

Вне вашего класса viewModel:

yourLiveDataInstance.observe(this@YourActivity, Observer {
            when(it){
                is ChildFirst -> {
                    // do stuff for ChildFirst
                }
                is ChildSecond ->{
                    // do stuff for ChildSecond
                }
            }
        })
...