我看过类似的问答,但没有找到我要找的东西 - 也许我遗漏了什么。
我想(在 Kotlin 类中)实现一个监听器属性。监听器只有一种方法,因此它是 lambda 友好的。
interface Listener {
fun onDone(id: String)
}
...
class Manager {
var listener: Listener? = null
}
当我想从 Java (8) 代码设置这个属性时,我可以使用 lambda 干净地完成它:
manager.setListener(id -> {
});
但是,在 Kotlin 中,我必须使用方法创建一个匿名对象:
manager.listener = object : OfflineManager.Listener {
override fun onDone(id: String) {
}
}
另一种选择,在 Kotlin 中使用函数引用:
var listener: ((String) -> Unit)? = null
在 Kotlin 中允许 nice lambda,但 Java lambda 需要一个返回值(即使该函数被定义为返回 Unit),这对 Java 开发人员来说很奇怪。
那么我怎样才能兼顾两者呢?
最佳答案
我相信没有直接的方法可以定义在 Java 和 Kotlin 中都“完全适用”的监听器。如果你想在 Java 中使用你的监听器,你必须坚持一个接口(interface),而 Kotlin 不支持 Kotlin 接口(interface)上的 SAM 转换:
[...] this feature [SAM conversions] works only for Java interop; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.
然而,您可以创建一个扩展方法(这样它就不会在 Java 中作为 Manager
的方法之一可见)将给定的 lambda 转换为匿名对象:
inline fun Manager.setListener(crossinline onDone: (String) -> Unit) {
listener = object : Listener {
override fun onDone(id: String) {
onDone(id)
}
}
}
通过这种方式,您可以在 Java 和 Kotlin 中保持它非常干净。
编辑: 上述的变体:
class Manager {
private var listener: Listener? = null
fun getListener(): Listener? = listener
fun setListener(listener: Listener?) {
this.listener = listener
}
}
var Manager.onDone: (String) -> Unit
get() = getListener()?.let { it::onDone } ?: {}
set(value) {
setListener(
object : Manager.Listener {
override fun onDone(id: String) {
value(id)
}
}
)
}
在这种情况下,在 Java 中,您仍然可以使用 setter 和 getter(必须显式编写)来引用监听器,并且基于 lambda 的字段在 Java 的 Manager
实例中不可见。在 Kotlin 中,listener
变量在 Manager
类之外是不可见的,它可以用作 lambda 字段。
然而,getListener
和 setListener
方法在 Kotlin 中都是可见和可访问的。此外,Kotlin 的 lambda 在转换为匿名对象时不会被内联。
关于java - 对 Java 和 Kotlin 友好的 Kotlin 监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57271884/