6

我正在尝试将侦听器从动作传递给类(适配器)。

在 java 中(来自动作的代码):

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

(来自适配器的代码)

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

有用。

现在我正在尝试翻译为 kotlin。我首先翻译动作(将动作翻译成 kotlin):

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

在这一点上仍然有效。适配器的代码仍在 java 中,类的代码在 kotlin 中。现在我将适配器翻译成 kotlin:

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

现在它不起作用。动作不编译。

错误:无法推断此参数“v”的类型。需要 View.OnClickListener。找到 (???) 单位。

我必须如何在这里做演员?为什么将参数从 kotlin 传递到 java 有效,而从 kotlin 传递到 kotlin 却不行?

4

2 回答 2

13

在调用 Java 代码的情况下,您将受益于用 Java 编写的单一方法接口的 SAM 转换。然后,当您将接口移植到 Kotlin 时,它还不允许这样做(Kotlin 当前假定您将使用函数引用和 lambda,而不是单个方法接口)。

问题与其他类似问题相同:Android - Kotlin - object must be declared abstract or implement abstract member

由于这是一个 Kotin 接口,因此您不能使用 SAM 转换为 Lambda,这就是为什么之前提供的其他答案不起作用的原因。如果这是一个 Java 接口,您可以这样做。您可以在KT-7770中跟踪 Kotlin 接口的 SAM 转换。

如果你想让这段代码更符合 Kotlin 的习惯,你会想要函数引用或 lambdas 而不是接口,你应该这样做而不是依赖 SAM 转换。您可以在高阶函数和 Lambda中了解更多相关信息。这超出了您更详细的问题范围。

因此,正如@joakim 在另一个答案中提到的,您必须传入一个实现此接口的类的实例。这称为对象表达式,如下所示:

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

或者实际上,您应该更改代码的 Kotlin 端口以接受对函数的引用,以便可以直接传入 lambda。这会更惯用,您可以按照最初尝试的方式调用它。

于 2017-05-26T17:06:41.217 回答
7

改变

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

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

})

并实现 View.OnClickListener 的方法

于 2017-05-25T22:08:06.797 回答