I have an abstract class, with a MediatorLiveData
object in it. This object has a number of sources, one of which depends on the childs class, and is abstract
in the parent class.
Adding the sources in an init
block causes a NullPointerException at runtime, because at the time the init block adds the source, it is still abstract (or so I have been led to believe).
Is there a way to use an abstract
LiveData
as a source for a MediatorLiveData
without having to set that source in a child class? I just want to override val
and be done with it, since I definitely will forget to call the addSources()
function at some time in the future.
(I am aware that this example is not the most useful way to do this exact thing, but I didn't want to add unneccesary complexity)
Example:
abstract class MyClass: ViewModel(){
private val _myMediator = MediatorLiveData<String>()
protected abstract val mySource: LiveData<String>
val myObservable: LiveData<String>
get() = _myMediator
// This will cause a NullPointerException at runtime
init{
_myMediator.addSource(mySource){ _myMediator.value = it }
}
//This should work, but requires this to be called in child class
protected fun addSources(){
_myMediator.addSource(mySource){ _myMediator.value = it }
}
}
class myChild: MyClass(){
override val mySource = Transformations.map(myRepository.someData) { it.toString() }
// This is where init { addSources() } would be called
}
After reading Stachu's anwser, I decided to go with this, which I didn't test butI think should work:
abstract class MyFixedClass: ViewModel(){
private val _myMediator: MediatorLiveData<String> by lazy{
MediatorLiveData<String>().apply{
addSource(mySource){ this.value = it }
}
}
protected abstract val mySource: LiveData<String>
val myObservable: LiveData<String>
get() = _myMediator
}
class MyChild: MyFixedClass(){
override val mySource = Transformations.map(myRepository.someData) { it.toString() }
}
how about using lazy evaluation, e.g. something like this
abstract class MyClass : ViewModel() {
private val _myMediator = MediatorLiveData<String>()
private val _mySource: LiveData<String> by lazy { mySource() }
protected abstract fun mySource(): LiveData<String>
val myObservable: LiveData<String>
get() = _myMediator
init {
_myMediator.addSource(_mySource) { _myMediator.value = it }
}
}
class myChild : MyClass() {
override fun mySource() = Transformations.map(myRepository.someData) { it.toString() }
}