6

Consider the following code:

val hwnd = Handler()
hwnd.postDelayed(object : Runnable {
        override fun run()
            hwnd.postDelayed(this, 5000)
        }
}, 5000)

This way, I can post the same Runnable to the Handler by using this (which refers to the Runnable) in the run() method. But how could I do the same using only a lambda expression?

val hwnd = Handler()
hwnd.postDelayed({
    //How to get "this" here?
}, 5000)

Is that even possible?

DVarga
  • 21,311
  • 6
  • 55
  • 60
Rafael
  • 3,042
  • 3
  • 20
  • 36

3 Answers3

4

It is not possible like that. You can refer to this discussion: Is “this” accessible in SAMs?

this in a lambda refers to the instance of the containing class, if any. A lambda is conceptually a function, not a class, so there is no such thing as a lambda instance to which this could refer.

The fact that a lambda can be converted into an instance of a SAM interface does not change this. Having this in a lambda mean different things depending on whether the lambda gets SAM-converted would be extremely confusing.

You can create a workaround (for example as suggested in the discussion): Create an extension function:

inline fun runnable(crossinline body: Runnable.() -> Unit) = object : Runnable {
    override fun run() = body()
}

then you can call it like

hwnd.postDelayed(runnable { hwnd.postDelayed(this, 5000) }, 5000)
DVarga
  • 21,311
  • 6
  • 55
  • 60
4

Since default lambda conversion gives you lambda with signature of () -> Unit, that means underlying Runnable is completely hidden.

You have to either deal with manual object creation, or write a wrapper extension function that will consume lambda with another signature:

// custom extension function for handler
inline fun Handler.postDelayed(delayMilis: Long, crossinline runnable: (Runnable) -> Unit) = postDelayed(object : Runnable{
    override fun run() {
        runnable(this)
    }
}, delayMilis)

Then at calling side you will be provided with Runnable object as lambda parameter (only parameter: it):

hwnd.postDelayed(5000){ 
    // it : Runnable
    hwnd.postDelayed(it, 5000)
}

Or if you want to get really fancy, change extension parameter to Handler.(Runnable) -> Unit, then you will be able to call:

hwnd.postDelayed(5000){ 
    // this : Handler, it : Runnable
    postDelayed(it, 5000)
}
Pawel
  • 15,548
  • 3
  • 36
  • 36
0

are you referring to the "qualified this" as described here:

https://kotlinlang.org/docs/reference/this-expressions.html

brismith
  • 696
  • 3
  • 18