NullPointerException (NPE) при использовании делегата свойства Kotlin с помощью
У меня есть класс, который принимает вводимые пользователем данные в текстовое поле и преобразует их в любой класс, используя предоставленные функции.
class GenericTextFieldDelegate<T>(
private val initBlock: () -> TextView,
private val getConversion: (String?) -> T?,
private val setConversion: (T?) -> String? = { it?.toString() }
) {
private val textView: TextView by lazy { initBlock() }
operator fun getValue(thisRef: Any?, property: KProperty<*>): T? =
getConversion(textView.text?.toString())
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
textView.text = setConversion(value)
}
}
Я сделал это так, что когда у меня есть TextView, я могу это сделать
class IntegerInputView @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attributeSet, defStyleAttr), DataInput<Int> {
override var value: Int? by GenericTextFieldDelegate(
{ inputET },
getConversion = { it?.toIntOrNull() },
setConversion = { it.toString() }
)
...
У меня есть фрагмент с указанным выше пользовательским представлением, и когда у меня есть
override var tareWeight: Kg?
get() = tareWeightInput.value
set(value) {
tareWeightInput.value = value
}
все работает нормально, я действительно хочу
override var tareWeight: Kg? by tareWeightInput
добавляя эти строки к IntegerInputView
...
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int? = value
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int?) {
this.value = value
}
override var value: Int? by GenericTextFieldDelegate(
...
Когда я создаю, запускаю и загружаю этот фрагмент, я получаю следующую трассировку стека. Где я ошибаюсь?
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Integer com.gameforeverything.storekeeper.customViews.IntegerInputView.getValue(java.lang.Object, kotlin.reflect.KProperty)' on a null object reference
at com.gameforeverything.storekeeper.fragments.weighInFragment.WeighInFragment.getGrossWeight(Unknown Source:7)
at com.gameforeverything.storekeeper.fragments.weighInFragment.WeighInPresenter.getNetWeight(WeighInPresenter.kt:40)
1 ответ
Ваша собственность делегирует себя (tareWeightInput
в этом примере) имеет значение null.
Вы можете сказать, что это так, изучив трассировку стека: она отмечает, что вызов метода, который не удался из-за NPE, был IntegerInputView.getValue
. Поскольку это вызов метода делегата свойства, который вызывается в делегате для получения значения свойства, мы знаем, что делегат должен иметь значение NULL.
Ваш делегат собственности является View
, поэтому я подозреваю, что он каким-то образом извлекается динамически, возможно, в результате findViewById
вызов. Вам необходимо убедиться, что переменная, содержащая делегат, не имеет значения NULL в момент ее получения. Рассмотрим аналогичный пример:
import kotlin.reflect.KProperty
class FooDelegate {
private var value: Int = 0
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int = value
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { this.value = value }
}
class Foo {
private lateinit var delegate: FooDelegate
val bar by delegate
init {
delegate = FooDelegate()
}
}
fun main() {
println(Foo().bar)
}
Это приводит к сбою, поскольку он пытается настроить делегата до инициализации переменной. В этом случае Kotlin выдает ошибку раньше, но в вашем примере это может быть замаскировано типами платформ из-за взаимодействия Kotlin/Java.