Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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([email protected], 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);
    }
};
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
333 views
Welcome To Ask or Share your Answers For Others

1 Answer

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)
        } 
    }
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...