FraK
FraK

Reputation: 1089

Kotlin setOnClickListener using method reference not working

I tried to use method reference the same way as in Java:

button.setOnClickListener(this::clickListener);

Using Kotlin:

button.setOnClickListener {this::clickListener}

However this doesn't work in Kotlin, the solution is to actually invoke the function withing the labmda expression:

button.setOnClickListener {clickListener()}

Why Kotlin doesn't accept the method reference in this case? Isn't the same principle as with Java?

Upvotes: 2

Views: 6419

Answers (3)

Zoe - Save the data dump
Zoe - Save the data dump

Reputation: 28228

Although this has already been answered, I'd like to expand the existing answers.

As TheWanderer already mentioned, curly braces here means the body of the lambda. Kotlin supports putting callbacks outside regular parenthesis.

This:

button.setOnClickListener {clickListener()}

Is equal to:

button.setOnClickListener({clickListener()})

which is equal to:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        clickListener();
    }
});

Or (Java 8 only):

button.setOnClickListener(view -> clickListener());

TL;DR: contents of function arguments are defined with (), and lambda bodies are defined with {} (just like with regular functions, classes, interfaces, etc.).

Now, first of all, a onClick method callback takes a view argument. If you use a standalone function, it needs to have this argument:

fun clickListener(view: View) { TODO("Place your listener code here") }

This is based on the naming -- if you're implementing OnClickListener, just pass this as the argument. You already have the listener and function, so you don't need to explicitly define one to pass. However, if you do implement OnClickListener, make sure to check the ID before taking action if you have multiple views using it as a listener.

If you are using methods, the next depends on how.

Using var or val functions

If your callback is defined as:

val listener = {view: View -> 
       TODO()               
    }

You can pass it like an argument:

button.setOnClickListener(listener)

OnClickListeners

If you have a var onClickListener: OnClickListener, the same as with var/val functions apply.

Using a function

If you have a fun clickListener, you'll have to add lambda to pass it. This is, just like with Java, using ::. However, you don't need to explicitly declare the scope like in Java. Which means either of these will work:

button.setOnClickListener(::clickListener);
button.setOnClickListener(this::clickListener);
// alternatively with a different target, if it's somewhere else. 

Further reading

Upvotes: 7

TheWanderer
TheWanderer

Reputation: 17824

The curly braces denote the contents of the lambda expression. Kotlin has already passed an instance of an OnClickListener behind the scenes and is providing the onClick() method to you.

If you want to pass a listener you have assigned to a variable, use parentheses:

button.setOnClickListener(clickListener)

If you want to use a function, it's the same as Java:

button.setOnClickListener(this::clickListener)

fun clickListener(v: View) {}

Upvotes: 5

Chan Myae Aung
Chan Myae Aung

Reputation: 547

You can do this in kotlin. Replace curly bracket with parenthesis.

btn.setOnClickListener (this::clicklistener)

fun clicklistener(v: View){}

Upvotes: 1

Related Questions