必须初始化变量“runnable”

2022-09-02 21:16:31

为什么 Kotlin 会抱怨这一点:

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

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

编译器抱怨说,在 Line 中,它是由处理程序再次发布的。这在普通的Java中确实有效:Variable 'runnable' must be initialized

private Handler handler = new Handler();

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

答案 1

Kotlin 认为一个属性在其初始值设定项结束之前未初始化,因此它不能在自己的初始值设定项内使用,即使在 lambdas 中也是如此。此语义类似于其初始值设定项内局部变量用法的限制

有几种解决方法:

  • 使用对象表达式,它允许您引用声明的对象:this

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

    这仅适用于作为lambdas替代品的接口,并且并不完全漂亮。

  • 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

推荐