I want to use MutableLiveData to observe some data from a ViewModel. The problem is that I use child and parent class, and there is some incompatibility with LiveData. An example of what I want to do in Kotlin:
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)
}
}
}
And here is in 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)
}
}
}
As you see, the problem is that the compiler don't consider the type the same for MutableLiveData<Child> and MutableLiveData<Parent>.
In Kotlin, I can cast the LiveData of a child as a parent. Even if there is a warning, the code run as intended: I can observe a MutableLiveData<Parent>.
Worse, in Java, it's impossible to compile, even with a cast.
So here is my question:
Why I can't use the LiveData of a child as the LiveData of a parent ? Is that something intended by the LiveData ?
Are they some eventual consequences of casting it with the kotlin 'as' ?
Why I can't use the LiveData of a child as the LiveData of a parent ? Is that something intended by the LiveData ?
In java the answer is quite simple: generic types in Java are invariant, meaning that List<String>
is not a subtype of List<Object>
(quoted from kotlin docs here)
Are they some eventual consequences of casting it with the kotlin 'as' ?
Kotlin is simply doing a compile time warning, but what happens in runtime is that your check is only agains the non generics part. That's why, I think (and if anyone know better than me, please explain! I'm courios about this), you can do it in Kotlin.
For a better explanation of what happens in kotlin (and also in Java) while using the generics type i recommend you to read the the full kotlin docs about generics here There is even plenty of articles about java generics casting like this one
EDIT: A way for resolving your problem could be this: declare a single live data and treat the childs in a simple manner like this:
val liveParent = MutableLiveData<Parent>()
val childFirst = ChildFirst()
val childSecond = ChildSecond()
and then return the correct child in the liveParent
while calling returnCorrectChild()
fun returnCorrectChild() {
if (shouldManageFirstChild) {
liveParent.value = firstChild
} else {
liveParent.value = secondChild
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With