Reputation: 3344
I'm a Kotlin noob (third day) and trying to add a listener to my class.
I'm currently using lambdas as in the following example and they work fine.
// Declare callback
class Controller {
var onAction = { -> }
}
// Use callback
myController.onAction = {
...
}
However, I really like the way Android's Button::setOnClickListener
is consumed in Kotlin code as follows (without having to use =
):
myButton.setOnClickListener {
awesomeObject.doSomething()
}
This makes me wonder:
How do I declare my listener so it can be used the Button::setOnClickListener
way?
What is the most 'Kotlinic'(*) way? Mine or Button::setOnClickListener
way?
(*) As in Pythonic :)
Upvotes: 4
Views: 7896
Reputation: 3344
For all you TL;DR people, here is a full example based on @Tenfour04's answer on how to use it without needing the =
sign (emulating SAM conversion):
// Declare callback using SAM's
class Controller {
// The listener
private var onAction: () -> Unit = {}
// This will allow you to use without the '='
// (as in required in Sergeys answer)
fun setOnAction(block: () -> Unit) { onAction = block }
// A listener with params
private var onActionWithParam: (String) -> Unit = {}
// This will allow you to use without the '='
// (as in required in Sergeys answer)
fun setOnActionWithParam(block: (String) -> Unit) { onActionWithParam = block }
}
// use the listener without '='
controller.setOnAction {
something.awesome()
}
controller.setOnActionWithParam { paramName ->
something.awesomeRequireStr(paramName)
}
However, bear in mind that the most Kotlin-idiomatic may be actually @Sergey's answer.
Upvotes: 1
Reputation: 93639
fun setOnAction(block: () -> Unit) { onAction = block }
and keep your onAction
var
.
But I suppose it's more Kotlin-idiomatic to just keep what you have. Properties are usually preferred over setter fun
s. The Android Button syntax is the result of SAM conversion of Java code. setOnClickListener
ends up more concise than onClickListener =
only because with the latter, the listener is a Java interface you have to name rather than a Kotlin function. It's really verbose to write:
button.onClickListener = OnClickListener {
//...
}
so the SAM conversion is nicer to use.
Upvotes: 3
Reputation: 30655
You can use next syntax to add a custom listener:
class Controller {
var onAction1: () -> Unit = {} // listener with default implementation without params and returns Unit
var onAction2: (() -> Unit)? = null // nullable listener without params and returns Unit
var onAction3: ((Int) -> String)? = null // listener with param of type Int and returns String object
}
Initializing listeners:
val controller = Controller()
controller.onAction1 = {
// your action
}
controller.onAction2 = {
// your action
}
controller.onAction3 = { intParam ->
// your action
"result" // return some String result
}
Calling listeners:
val controller = Controller()
controller.onAction1()
controller.onAction2?.invoke()
val result: String? = controller.onAction3?.invoke(20)
Upvotes: 4