【问题标题】:Variable 'runnable' must be initialized必须初始化变量“可运行”
【发布时间】:2016-07-28 08:45:32
【问题描述】:

为什么 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 中的 Variable 'runnable' must be initialized 是由处理程序再次发布的。 这在纯 Java 中确实有效:

private Handler handler = new Handler();

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

【问题讨论】:

  • 你不担心它是一个周期性的参考吗?
  • 我应该这样做吗?它背后的想法是这个 Runnable 应该每 5 秒执行一次。还是我遗漏了一些非常明显的东西?!

标签: java android kotlin


【解决方案1】:

Kotlin 认为一个属性在其初始化程序结束之前是未初始化的,因此它不能在其自己的初始化程序中使用,即使在 lambdas 中也是如此。这种语义类似于local variable usage inside its initializer 的限制。

有几种解决方法:

  • 使用object expression,它可以让您引用声明对象的this

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

    这仅适用于接口作为 lambda 的替代品,而且完全不是很漂亮。

  • 使用lateinit vardelegated propertyDelegates.notNull()

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

    同样的初始化器将适用于这个声明:

    private var runnable: Runnable by Delegates.notNull()
    
  • 自行实现和使用self-reference for initializers

    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
    

    【讨论】:

    • 您也可以使用只读属性来代替函数:private val runnableCopy get() = runnable
    猜你喜欢
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多