Why does Kotlin complains about this:
class MyActivity : Activity {
private var handler:Handler = Handler()
private var runnable: Runnable = Runnable {
/* Do something very important */
handler.postDelayed(this@MyActivity.runnable, 5000)
}
}
Compiler complains that Variable 'runnable' must be initialized
in the Line were it's posted again by handler.
This does work in plain Java:
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
@Override
public void run() {
handler.postDelayed(runnable, 5000);
}
};
Kotlin considers a property uninitialized until the end of its initializer, therefore it cannot be used inside its own initializer, even in lambdas. This semantics is similar to the limitation of local variable usage inside its initializer.
There are several workarounds:
Use object expression which lets you reference this
of the declared object:
private var runnable: Runnable = object : Runnable {
override fun run() {
/* Do something very important */
handler.postDelayed(this, 5000)
}
}
This works well only for interfaces as a replacement for lambdas and is not very pretty altogether.
Use lateinit var
or a delegated property with Delegates.notNull()
:
private lateinit var runnable: Runnable
init {
runnable = Runnable {
/* Do something very important */
handler.postDelayed(runnable, 5000)
}
}
The same initializer will work with this declaration:
private var runnable: Runnable by Delegates.notNull()
Implement and use self-reference for initializers on your own:
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
}
And then you can write something like
private var runnable: Runnable = selfReference {
Runnable {
/* Do something very important */
handler.postDelayed(self, 5000)
}
}
You can also use
private var runnable: Runnable = Runnable {
/* Do something very important */
handler.postDelayed(runnable(), 5000)
}
private fun runnable() = runnable