Skip to content
Advertisement

Using functional interfaces with function types in Kotlin

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
}
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement