Недавно я столкнулся с NPE, реализующим новый класс Android ViewModel
. Исправление проблемы заняло немного больше времени из-за чего-то, чего я до сих пор не понимал в Kotlin.
Объявление значений членов класса после блока init
не будет инициализировано при выполнении блока init
.
Пример:
class MyClass { init { updateAnswer("42") } val answer by lazy { MutableLiveData<String>() } fun updateAnswer(newAnwser: String) { answer.value = newAnwser } }
Это вызовет NPE, поскольку делегат answer
не был инициализирован в блоке init
.
Попытка сделать это:
class MyClass { init { answer.value = "42" } val answer by lazy { MutableLiveData<String>() } }
будет пойман редактором и компилятором.
Это можно легко исправить, изменив порядок объявления члена данных.
class MyClass { val answer by lazy { MutableLiveData<String>() } init { updateAnswer("42") } fun updateAnswer(newAnwser: String) { answer.value = newAnwser } }
На этот раз делегат answer
будет установлен в блоке init
Спасибо за прочтение, но я хотел бы отметить, что пример, в котором я поймал это, был более сложным, чем этот упрощенный пример. В моем примере использовались EventBu, о которых я писал в предыдущем посте. Мой пример выглядел примерно так:
class MyClass { init { EventBus.getDefault().register(this) } val answer by lazy { MutableLiveData<MyDomainObject>() } @Subscribe(sticky = true, threadMode = ThreadMode.BACKGROUND) protected fun bind(newAnwser : MyDomainObject) { answer.value = newAnwser; } }
Я не осознавал, что к этому времени Eventbus
уже имел MyDomainObject
и, таким образом, вызывал функцию bind()
синхронно с вызовом EventBus.getDefault().register(this)
.
Обо мне
Я являюсь подрядчиком разработчиков Kotlin/Java для Android. Мне всегда интересно узнать о вашем проекте и о том, чем я могу помочь друг другу. www.wedgetech.co.uk