Подтвердить что ты не робот

Переменная "runnable" должна быть инициализирована

Почему Котлин жалуется на это:

class MyActivity : Activity {
  private var handler:Handler = Handler()

  private var runnable: Runnable = Runnable {
    /* Do something very important */
    handler.postDelayed([email protected], 5000)
  }
}

Компилятор жалуется, что Variable 'runnable' must be initialized в Линии был снова отправлен обработчиком. Это работает в простой Java:

private Handler handler = new Handler();

private Runnable runnable = new Runnable() {
    @Override
    public void run() {
        handler.postDelayed(runnable, 5000);
    }
};
4b9b3361

Ответ 1

Kotlin считает свойство неинициализированным до конца его инициализатора, поэтому он не может использоваться внутри своего собственного инициализатора даже в лямбдах. Эта семантика аналогична ограничению использования локальной переменной внутри ее инициализатора.

Существует несколько способов:

  • Используйте выражение объекта, которое позволяет ссылаться на this объявленного объекта:

    private var runnable: Runnable = object : Runnable {
        override fun run() {
            /* Do something very important */
            handler.postDelayed(this, 5000)
        }
    }
    

    Это хорошо работает только для интерфейсов в качестве замены для лямбда и совсем не совсем красиво.

  • Используйте lateinit var или делегированное свойство с Delegates.notNull():

    private lateinit var runnable: Runnable
    init {
        runnable = Runnable { 
            /* Do something very important */
            handler.postDelayed(runnable, 5000)
        }
    }
    

    Тот же инициализатор будет работать с этим объявлением:

    private var runnable: Runnable by Delegates.notNull()
    
  • Внедрить и использовать самостоятельную ссылку для инициализаторов самостоятельно:

    class SelfReference<T>(val initializer: SelfReference<T>.() -> T) {
        val self: T by lazy {
            inner ?: throw IllegalStateException("Do not use `self` until initialized.")
        }
    
        private val inner = initializer()
    }
    
    fun <T> selfReference(initializer: SelfReference<T>.() -> T): T {
        return SelfReference(initializer).self
    }
    

    И тогда вы можете написать что-то вроде

    private var runnable: Runnable = selfReference { 
        Runnable {
            /* Do something very important */
            handler.postDelayed(self, 5000)
        } 
    }
    

Ответ 2

Вы также можете использовать

private var runnable: Runnable = Runnable {
    /* Do something very important */
    handler.postDelayed(runnable(), 5000)
}

private fun runnable() = runnable