Search code examples
androidkotlinnullpointerexceptionnull

Kotlin property declared as non-nullable is nullable even if it has initialized value


This is really interesting situation. I have some android custom view. It has some property 'state' for changing the drawable state of checkbox based on this property. As you can see, this property is declared as non-nullable and I initialize it with default value '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))
        }
}

But when we're going to use this view, it's crashing with this exception:

kotlin.NoWhenBranchMatchedException

I had tried to debug the when-expression and I have noticed that inside 'onCreateDrawableState' method it is not initialized with default value 'State.Regular', but with 'null', and that is why we have this 'NoWhenBranchMatchedException'.

Do you have any ideas why is this property initialized with null and how to fix this?


Solution

  • The problem is that the AppCompatCheckBox's constructor (which calls onCreateDrawableState) is called before SomeCustomView's which initializes the property. If you didn't need a custom setter you could use lateinit and initialize it inside onCreateDrawableState; with it, consider these workarounds (but they may be too complex for just this one place).