Когда выражение не работает с классом enum в onCreateDrawableState - android, kotlin - PullRequest
0 голосов
/ 26 января 2019

Я не могу понять, почему это выбрасывает NPE на линии when (colorState). Если я удаляю enum class и заменяю значения целыми числами, все работает нормально.

class ColorChangerButton(context: Context, attrs: AttributeSet) : AppCompatImageButton(context, attrs) {

    enum class ColorState {ACCENT, STRONG, WEAK}

    private val stateAccent = intArrayOf(R.attr.state_accent)
    private val stateStrong = intArrayOf(R.attr.state_strong)
    private val stateWeak = intArrayOf(R.attr.state_weak)

    var colorState = ColorState.ACCENT
        set(value) {
            if (field != value) {
                field = value
                refreshDrawableState()
            }
        }

    override fun onCreateDrawableState(extraSpace: Int): IntArray {
        val state = super.onCreateDrawableState(extraSpace + 1)

        when (colorState) {
            ColorState.ACCENT -> View.mergeDrawableStates(state, stateAccent)
            ColorState.STRONG -> View.mergeDrawableStates(state, stateStrong)
            ColorState.WEAK -> View.mergeDrawableStates(state, stateWeak)
        }

        return state
    }
}

Трассировка стека:

 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.test.uiplayground.buttons.ColorChangerButton$ColorState.ordinal()' on a null object reference
    at com.test.uiplayground.buttons.ColorChangerButton.onCreateDrawableState(ColorChangerButton.kt:28)
    at android.view.View.getDrawableState(View.java:15953)
    at android.view.View.setBackgroundDrawable(View.java:16188)
    at androidx.appcompat.widget.AppCompatImageButton.setBackgroundDrawable(AppCompatImageButton.java:122)
    at android.view.View.setBackground(View.java:16125)
    at android.view.View.<init>(View.java:4090)
    at android.widget.ImageView.<init>(ImageView.java:139)
    at android.widget.ImageButton.<init>(ImageButton.java:86)
    at android.widget.ImageButton.<init>(ImageButton.java:82)
    at androidx.appcompat.widget.AppCompatImageButton.<init>(AppCompatImageButton.java:73)
    at androidx.appcompat.widget.AppCompatImageButton.<init>(AppCompatImageButton.java:69)
    at com.test.uiplayground.buttons.ColorChangerButton.<init>(ColorChangerButton.kt:9)

Как я уже говорил выше, если я заменю перечислимый класс на целое число, то он прекрасно работает:

class ColorChangerButton(context: Context, attrs: AttributeSet) : AppCompatImageButton(context, attrs) {

    private val stateAccent = intArrayOf(R.attr.state_accent)
    private val stateStrong = intArrayOf(R.attr.state_strong)
    private val stateWeak = intArrayOf(R.attr.state_weak)

    var colorState = 1
        set(value) {
            if (field != value) {
                field = value
                refreshDrawableState()
            }
        }

    override fun onCreateDrawableState(extraSpace: Int): IntArray {
        val state = super.onCreateDrawableState(extraSpace + 1)

        when (colorState) {
            1 -> View.mergeDrawableStates(state, stateAccent)
            2 -> View.mergeDrawableStates(state, stateStrong)
            3 -> View.mergeDrawableStates(state, stateWeak)
        }

        return state
    }
}

Решено, дополнительное объяснение:

  1. По причине того, что NPE брошен, смотрите принятый ответ.
  2. Целочисленная часть вводила в заблуждение. Java устанавливает неинициализированные переменные в значение по умолчанию (если только локальные или блочные переменные не вызывают ошибку, говоря, что она не инициализирована). Для целого числа это значение равно 0. Таким образом, оно прошло все 3 условия при первом вызове. Если я добавлю 0 -> View.mergeDrawableStates(state, stateAccent) case, то получу еще один NPE, на этот раз, потому что stateAccent еще не инициализирован - что на данный момент имеет смысл.

1 Ответ

0 голосов
/ 26 января 2019

Это сгенерированный код Java для исходного файла Kotlin:

  public ColorChangerButton(@NotNull Context context, @NotNull AttributeSet attrs) {
      Intrinsics.checkParameterIsNotNull(context, "context");
      Intrinsics.checkParameterIsNotNull(attrs, "attrs");
      super(context, attrs);                  <---------- super will be called first
      this.stateAccent = new int[0];
      this.stateStrong = new int[0];
      this.stateWeak = new int[0];
      this.colorState = ColorChangerButton.ColorState.ACCENT;
   }

Переменные экземпляра даже не инициализируются до тех пор, пока не будет сделан вызов super(). NPE возникает, когда суперструктор вызывает onCreateDrawableState.

...