Свойство Kotlin, объявленное как не допускающее значение NULL, может иметь значение NULL, даже если оно имеет инициализированное значение.

Это действительно интересная ситуация. У меня есть пользовательский вид Android. У него есть некоторое свойство «состояние» для изменения отображаемого состояния флажка на основе этого свойства. Как видите, это свойство объявлено как не допускающее значение NULL, и я инициализирую его значением по умолчанию «State.Regular».

class SomeCustomView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatCheckBox(context, attrs) {

    sealed class State {
        object Regular : State()
        object Specific : State()
    }

    // todo: it will be nice to implement statesaving
    //       but it's okay for now
    var state: State = State.Regular
        set(value) {
            field = value
            refreshDrawableState()
        }

    override fun onCreateDrawableState(extraSpace: Int): IntArray =
        super.onCreateDrawableState(extraSpace + 1).apply {
            val stateAttrRes = when(state) {
                State.Specific -> R.attr.some_custom_view_specific
                State.Regular -> R.attr.some_custom_view_regular
            }

            View.mergeDrawableStates(this, intArrayOf(stateAttrRes))
        }
}

Но когда мы собираемся использовать это представление, происходит сбой с этим исключением:

kotlin.NoWhenBranchMatchedException

Я пытался отладить выражение when и заметил, что внутри метода onCreateDrawableState он инициализируется не значением по умолчанию State.Regular, а значением null, и поэтому у нас есть это NoWhenBranchMatchedException.

У вас есть идеи, почему это свойство инициализируется нулем и как это исправить?


person Kirill    schedule 07.03.2020    source источник
comment
Небольшой лайфхак, чтобы исправить это: добавьте elvis внутри, когда: when(state ?: State.Regular) ... Но это костыль, и Android Studio также будет выделять его как неиспользуемый, но он работает во время выполнения.   -  person Kirill    schedule 07.03.2020


Ответы (2)


Проблема в том, что конструктор AppCompatCheckBox (который вызывает onCreateDrawableState) вызывается перед конструктором SomeCustomView, который инициализирует свойство. Если вам не нужен пользовательский сеттер, вы можете использовать lateinit и инициализировать его внутри onCreateDrawableState; с ним рассмотрите эти обходные пути (но они могут быть слишком сложными только для этого одного места).

person Alexey Romanov    schedule 08.03.2020

Это не только для Котлина. У вас есть эта проблема и в Java. Поэтому лучше игнорировать его, проверив, что он не равен нулю, или установить значение по умолчанию.

OnCreateDrawableState вызывается перед блоком инициализации в Kotlin. После инициализации ваши свойства будут инициализированы

person Hassan Alizadeh    schedule 07.03.2020