Passing a listener object as a function parameter in kotlin

*爱你&永不变心* 提交于 2019-11-27 07:55:09

问题


I'm trying to pass a listener from an action to a class (an adapter).

In java (code from the Action):

  private void setListeners() {
    adapterRecyclerView.setListener(
            new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    SomeCodehere....
                }
            });
}

(code from the adapter)

public void setListener(View.OnClickListener listener) {
    this.listener = listener;
}

It works.

Now I'm trying to traslate to kotlin. I translate first the action (translation the action to kotlin):

    private fun setListeners() {
    // !! is not fine i know
    adapterRecyclerView!!.setListener  { v  ->
                          SomeCodehere....
    }
}

At this point still works. With the code of the adapter still in java and code of the class in kotlin. Now I translate the adapter to kotlin:

fun setListener(listener: View.OnClickListener) {
    this.listener = listener 
}

Now it doesn't work. The Action does not compile.

Error: cannot infer a type for this parameter "v". required View.OnClickListener. found (???) Unit.

How I must do the cast here? Why passing the parameter from kotlin to java works and from kotlin to kotlin it does not?


回答1:


In the case of calling Java code you are benefitting from SAM conversion for single method interfaces written in Java. Then when you port the interface to Kotlin it does not allow this yet (Kotlin currently assumes you would use function references and lambdas instead of a single method interface).

The problem is the same as from this other similar question: Android - Kotlin - object must be declared abstract or implement abstract member

Since this is a Kotin interface, you cannot use the SAM conversion to a Lambda so that is why the other answer previously provided does not work. If this was a Java interface, you could do that. You can track SAM conversions for Kotlin interfaces in KT-7770.

If you wanted this code to be more idiomatic Kotlin you would want function references or lambdas instead of interfaces, and you should just do that instead of relying on SAM conversion. You can read more about that in Higher-Order Functions and Lambdas. This is outside the scope of your question to go into more detail.

Therefore as mentioned in another answer by @joakim, you must pass in a instance of a class that implements this interface. This is called an Object Expression and looks like:

object : View.OnClickListener {
    override fun onClick(v: View) {...}
})

Or realistically you should change your Kotlin port of the code to accept a reference to a function so that a lambda can be passed in directly. That would be more idiomatic and you would be able to call it as you were originally attempting.




回答2:


Change

adapterRecyclerView!!.setListener  { v  ->
                      SomeCodehere....
}

to

adapterRecyclerView!!.setListener(object : View.OnClickListener {

})

and implement the methods of View.OnClickListener



来源:https://stackoverflow.com/questions/44190468/passing-a-listener-object-as-a-function-parameter-in-kotlin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!