2016-04-07 125 views
14

为什么科特林抱怨这一点:变量“可运行”必须初始化

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); 
    } 
}; 
+1

难道你不关心它是一个循环引用或东西吗? – AndroidEx

+0

我应该吗?背后的想法是,这个Runnable应该每5秒执行一次。或者我错过了一些非常明显的东西?! – GeneralOfTheFelixLegions

回答

13

科特林认为未初始化的属性,直到它的初始化结束,因此不能在自己的初始化内使用,即使在lambda表达式。这种语义类似于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) 
        } 
    } 
    
+0

感谢您让我走上正轨。 – tango24

1

您还可以使用

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

private fun runnable() = runnable 
+0

而不是一个函数,你也可以使用只读属性: 'private val runnableCopy get()= runnable' – Heinrich