Kotlin - How to pass a Runnable as this in Handler

Viewed 10165

I'm beginner in kotlin. I try to create a task that will repeat every 2 seconds. So I created something like this.

val handler = Handler()
    handler.postDelayed(Runnable {
        // TODO - Here is my logic

        // Repeat again after 2 seconds
        handler.postDelayed(this, 2000)
    }, 2000)

But in postDelayed(this) it gives error - required Runnable!, found MainActivity. I've tried even this@Runnable but it didn't work.

But when I write the same function like this, it works

val handler = Handler()
    handler.postDelayed(object : Runnable {
        override fun run() {
            // TODO - Here is my logic

            // Repeat again after 2 seconds
            handler.postDelayed(this, 2000)
        }
    }, 2000)

So why the this keyword doesn't work in first function, but in second function it works good?

4 Answers

You have several options to go about here:

  1. make both the runnable and the handler be in the same scope

        //class scope
        val handler = Handler()
        val runnable = object : Runnable {
           override fun run () {
             handler.removeCallbacksAndMessages(null) 
             //make sure you cancel the 
              previous task in case you scheduled one that has not run yet
             //do your thing
    
             handler.postDelayed(runnable,time)
          }
       }
    

then in some function

handler.postDelayed(runnable,time)
  1. You can run a timertask, which would be better in this case

     val task = TimerTask {
        override fun run() {
         //do your thing
        }
     }
    
     val timer = Timer()
    
     timer.scheduleAtFixedRate(task,0L, timeBetweenTasks)
    

The first one is a function that accepts a lambda and returns a Runnable. In this case this means nothing.

The second one you're defining an anonymous object that implements Runnable. In this case this refers to that object instance.

The below example will work.

val runnable = object : Runnable { 
        override fun run() {
         
            handler.postDelayed(this,1000)
        }
    }

In your case , when use this it means "local final class <no name provided> : Runnable" , refer to a header runnable.

runnable=object : Runnable {
            override fun run() {
                // i is a counter
                println("No. "+i++)
                // Repeat again after 2 seconds
                handler.postDelayed(this, 2000)
            }
        }
        handler.postDelayed(runnable,0)

Where runnable is used inside of a method. As Handler() is deprecated, we must use like this:

var handler: Handler = Handler(Looper.getMainLooper())
var runnable: Runnable = Runnable { }

Moreover, anywhere you can stop this method by:

handler.removeCallbacks(runnable)
Related