Trying to understand OnClickListener

I know how to set up a button click listener.
(1) First create an instance of OnClickListener and override the onClick method with a custom process
(2) Assign that OnClickListener to the button using setOnClickListener method of the button, and pass the OnClickListener object as the argument.

But I am also able to achieve the same result without creating an OnClickListener object. I am trying to understand why this method works.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val button: Button = findViewById<Button>(R.id.button)
        button.setOnClickListener(){ Toast.makeText(this,"Button Pressed",Toast.LENGTH_SHORT).show()}
    }
}
2 Likes

Here you go:

Thanks for that response. The only issue I have is that setOnClickListener() is not a functional interface. It is a method under View. If it had been View.OnClickListener(){ Toast.makeText(this)… } then that would be entirely understandable. But that is not what this is.

edit: I misread what confuses you here. Below answer by @al3c makes much more sense.

Well, I think the documentation about SAM conversions is a little misleading. First it says: “An interface with only one abstract method is called a functional interface” and then: “To declare a functional interface in Kotlin, use the fun modifier.”. I think these two sentences contradict themselves, because first says any interface with a single abstract function is a functional interface and second says it has to be marked with fun.

But the main problem here is different. This article is only about SAM conversions for Kotlin interfaces and SAM conversions for Java interfaces were documented in another place :stuck_out_tongue: Calling Java from Kotlin | Kotlin I believe this is for historical reasons. Initially, Kotlin had SAM conversions for Java interfaces only. Then fun interfaces were added. I guess the documentation needs to be reworked.

Anyway, SAM conversions for Java interfaces are less “strict” than for Kotlin interfaces. You can use any interface with single abstract method, it doesn’t have to be marked in any way, it doesn’t require @FunctionalInterface, etc.

2 Likes

View.setOnClickListener is just a method on View which is not a functional interface.

However View.OnClickListener is a functional interface, and that is the argument View.setOnClickListener wants.

So when you call View.setOnClickListener with a lambda kotlin magically converts that to an instance of View.OnClickListener

Yes, thank you. This “magical” conversion is what I guessed was happening. I don’t know about the other newbies, but this inference makes learning Kotlin very difficult, at least for me. This is like in a real language where the context of a phrase word changes its real meaning.

1 Like

I wouldn’t use “magical conversion” to refer to any kind of casting in Kotlin. Kotlin, as Java, is a very well documented language, although, most of the time we don’t check all the embeddeg classes documentation of any language, I’m saying that 'cause does anyone really knows how an object of type Any is casted to String or Double, or any specific object type? Sometimes when I’m debugging a code it happens to open the code of my parent class (like debugging a method of a view I created, and the IDE show me view.kt code), so each method, each type of operation is avaiable for anyone check it. But this, in my opinion, didn’t make more or less difficult to learn Kotlin, after a while I get a better understand of lambdas(which Kotil uses a lot, that’s a fact) and I could code as in Java or Swift.

Hi
Old post.

I wrote this

typealias MyClickHandler = (Int) -> Unit

class MyButton(val texte: String) {
    var myClick: MyClickHandler = {x: Int ->
        repeat(x) {
            println("C'est cela ${this.texte}")
        }
    }
    fun setOnMyClick(x: MyClickHandler): Unit {
        this.myClick = x
    }
}



var w=MyButton("bonjour")
w.myClick(4)
w.setOnMyClick(fun(x: Int){repeat(x){println("That's it Hello")}})
w.myClick(2)

is View.setOnClickListener implemented as my code?