In kotlin, we can use setOnClickListener()
like this:
view.setOnClickListener { println("Hello") }
But if I define my own interface, I can only pass anonymous object like this:
obj.setMyListener(object: MyListener() {
...
})
I just wondering how they make setOnClickListener()
accept a function rather than an anonymous object.
In Kotlin, you can provide default values to parameters in function definition. If the function is called with arguments passed, those arguments are used as parameters.
Only one parameter can be marked as vararg . If a vararg parameter is not the last one in the list, values for the subsequent parameters can be passed using named argument syntax, or, if the parameter has a function type, by passing a lambda outside the parentheses.
Kotlin functions are first-class, which means they can be stored in variables and data structures, and can be passed as arguments to and returned from other higher-order functions.
According to Kotlin documentations about Java interop, for a functional interface defined in Java, you can use a SAM conversion.
Just like Java 8, Kotlin supports SAM conversions. This means that Kotlin function literals can be automatically converted into implementations of Java interfaces with a single non-default method, as long as the parameter types of the interface method match the parameter types of the Kotlin function.
val runnable = Runnable { println("This runs in a runnable") }
val executor = ThreadPoolExecutor()
// Java signature: void execute(Runnable command)
executor.execute { println("This runs in a thread pool") }
However, Kotlin has functional types, therefore SAM conversion doesn't work for interfaces defined in Kotlin:
Also note that this feature works only for Java interop; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.
Make the method receive a function as argument:
// Example listener receives a bool and return unit.
fun setMyListener(listener: (isChecked: Bool) -> Unit) { ... }
// Usage:
obj.setMyListener { isChecked -> }
Use type alias (only supported in Kotlin 1.1+):
typealias MyListener = (Bool) -> Unit
fun setMyListener(listener: MyListener) { ... }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With