【问题标题】:How to declare an interface that works with lambda? [duplicate]如何声明一个适用于 lambda 的接口? [复制]
【发布时间】:2018-11-01 09:47:57
【问题描述】:

我声明了一个这样的简单接口:

   interface OnSomethingReadyListener {
        fun onSomethingReady()
    }

当然还有二传手:

private val onSomethingReadyListeners = ArrayList<OnSomethingReadyListener>()

fun addOnSomethingReadyListener(callback: OnSomethingReadyListener) {
    onSomethingReadyListeners.add(callback)
}

但后来我发现我不能使用 lambda:

something.addOnShopDataReadyListener { progressbar.visibility = View.GONE }

IDE 给了我一个错误:

Type mismatch.
Required: SomeClass.OnSomethingReadyListener
Found:    () -> Unit

假设我想坚持使用 lambda 而不是匿名类 (object : OnSomethingReadyListener {...})。我应该如何声明OnSomethingReadyListener

【问题讨论】:

  • 您声称只有在方法没有参数时才会发生这种情况,这并没有在我这边进行检查。无论有无参数,它都不起作用。
  • @MarkoTopolnik 对不起,你是对的。我已经编辑了问题。

标签: android lambda interface kotlin


【解决方案1】:

你必须这样声明函数:

fun addOnSomethingReadyListener(block: (OnSomethingReadyListener) -> Unit)

然后你可以这样称呼它:

addOnSomethingReadyListener {
  // TODO
}

【讨论】:

    【解决方案2】:

    SAM(单一抽象方法)转换仅支持 Java 接口,不支持 Kotlin 接口。

    The documentation 陈述了这个推理:

    还请注意,此功能仅适用于 Java 互操作;由于 Kotlin 具有适当的函数类型,因此不需要将函数自动转换为 Kotlin 接口的实现,因此不受支持。

    KT-7770 requests this functionality,如果你想跟踪它是否被考虑。

    实现您想要的建议的方法是将OnSomethingReadyListener 替换为() -&gt; Unit 类型的参数,如下所示:

    private val onSomethingReadyListeners = ArrayList<() -> Unit>()
    
    fun addOnSomethingReadyListener(callback: () -> Unit) {
        onSomethingReadyListeners.add(callback)
    }
    

    然后您可以使用类似的方法调用这些侦听器

    onSomethingReadyListeners.forEach { it.invoke() }
    

    【讨论】:

    • 谢谢!还有一个问题,如果出于可读性原因,我想声明自己的接口(例如,使用多个命名参数,但只有一种方法),我不能再使用 lambda 了吗?我尝试了@LucaNicoletti 的答案,但它不起作用。
    • “SAM 转换”是您想要的技术术语:将接口类型转换为等效的函数类型。这个答案引用了权威来源的引述,解释说 Kotlin 接口支持此功能,只是为了方便与 Java 进行互操作。换句话说,Kotlin 团队希望你使用函数类型。
    猜你喜欢
    • 2011-02-25
    • 2012-06-15
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 2014-06-25
    相关资源
    最近更新 更多