When calling Java code from Kotlin, there is SAM conversion so that Java code like this:
adapter.setOnClickListener(new OnClickListener() { @Override public void onClick(View view, int position) { // Do stuff here } });
Can look like this:
adapter.setOnClickListener { view, position -> // Do stuff }
Now, I’m working on a Kotlin project and I want to define a functional interface as an event listener:
interface OnSomeActionListener { fun onSomeAction(parameter1: Int, parameter2: String) }
In SomeClass
I have a function to set the listener:
... private var onSomeActionListener: OnSomeActionListener? = null fun setOnSomeActionListener(listener: OnSomeActionListener) { onSomeActionListener = listener } ...
And when I create an instance of this class and try to invoke the setter function, I do it like so:
val thing = SomeClass() thing.setOnSomeActionListener(object : OnSomeActionListener { override fun onSomeAction(parameter1: Int, parameter2: String) { // Do stuff here } })
I’m aware that Kotlin has function types therefore doesn’t support SAM conversion from various sites such as this one.
I’ve read a little about function types but I have not used them before.
How would I rewrite my code so that I can invoke the setter function like this?
val thing = SomeClass() thing.setOnSomeActionListener { parameter1, parameter2 -> // Do stuff here }
.
Advertisement
Answer
A function type looks like this:
(Parameters) -> ReturnType
In your case, instead of using the interface type, you could use (View, Int) -> Unit
. It would look something like this:
private var onSomeActionListener: ((View, Int) -> Unit)? = null fun setOnSomeActionListener(listener: (View, Int) -> Unit) { onSomeActionListener = listener } private fun callSomeActionListener(view: View, position: Int) { onSomeActionListener?.invoke(view, position) }
Add names
In functional types you can also specify names for the parameters. This doesn’t change much under the hood but they can add some clarity here and in the calling code, which is nice.
(view: View, position: Int) -> Unit
Using a type alias
To avoid having to type (View, Int) -> Unit
every time, you can define a typealias:
typealias OnSomeActionListener = (view: View, position: Int) -> Unit
So that your code now looks like this again:
private var onSomeActionListener: OnSomeActionListener? = null fun setOnSomeActionListener(listener: OnSomeActionListener?) { onSomeActionListener = listener }
And to call it:
val thing = SomeClass() thing.setOnSomeActionListener { view, position -> // Do stuff here }