Возможно, чтоб not null LiveData возвращала null значение?

Рейтинг: 1Ответов: 1Опубликовано: 09.05.2023

Есть LiveData на котороую подписывается View вот так

введите сюда описание изображения

В аналитике вижу отчет об краше в котором говориться

Location: MyFile.kt line 116 in MyFragment$setupObservers$2.invoke
Exception: java.lang.NullPointerException
Message: it must not be null

Функция enableContinueButton(state: Boolean) не принимает, null значения, так же как LiveData не возвращает null

...
protected val _fieldsValidated = MutableLiveData<Boolean>()
val fieldsValidated: LiveData<Boolean> =  _fieldsValidated
...

Но судя по ошибке LiveData все же возвращает null в 116й строке и случается краш.

Вопрос: как это возможно?

Ответы

▲ 0Принят

В общем проблема заключается в том, что MutalbeLiveData написана на джаве как результат получается, что даже not-null LiveData все равно очень хорошо принимает null значения и когда обзервер подпишиться на нее то неожиданно null будет возвращен в not-null LiveData.

Как решить проблему? Есть два возможных способа, первый в котором null просто не будет прилитать в обзервер и второй где LiveData будет крашиться на моменте где значение присваивается (.value = null), а не в обзервере, то есть можно будет легче понять от куда прилетает null

Первое решение:

class NonNullMediatorLiveData<T> : MediatorLiveData<T>()

fun <T> NonNullMediatorLiveData<T>.observe(owner: LifecycleOwner, observer: (t: T) -> Unit) {
    this.observe(owner, Observer {
        it?.let(observer)
    })
}

fun <T> LiveData<T>.nonNull(): NonNullMediatorLiveData<T> {
    val mediator: NonNullMediatorLiveData<T> = NonNullMediatorLiveData()
    mediator.addSource(this) { it?.let { mediator.value = it } }
    return mediator
}

использование:

...
myLiveData.nonNull().observe(...) { ... }
...

Второе решение:

class NonnullableMutableLiveData<T: Any>: MutableLiveData<T>() {
    override fun postValue(value: T) = super.postValue(value)
    override fun setValue(value: T) = super.setValue(value)
}

Использование:

...
val myLiveData: NonnullableMutableLiveData....
...

Ну и естественно в зависимости от ситуации испозовать одно или другое.