Java和Kotlin友好的Kotlin侦听器
我看过类似的问答,但没有找到我想要的——也许我错过了什么 我想(在Kotlin类中)实现一个侦听器属性。侦听器只有一个方法,因此它是lambda友好的Java和Kotlin友好的Kotlin侦听器,java,kotlin,interop,Java,Kotlin,Interop,我看过类似的问答,但没有找到我想要的——也许我错过了什么 我想(在Kotlin类中)实现一个侦听器属性。侦听器只有一个方法,因此它是lambda友好的 interface Listener { fun onDone(id: String) } ... class Manager { var listener: Listener? = null } 当我想从Java(8)代码中设置此属性时,我可以使用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需要返回值(即使函数定义为返回单元),这对于Java开发人员来说是陌生的
那么,我如何才能充分利用这两者呢?我相信没有一种简单的方法可以定义这样一个在Java和Kotlin中都“完全适用”的监听器。如果要在Java中使用侦听器,则必须坚持使用接口,并且Kotlin不支持Kotlin接口上的SAM转换: […]此功能[SAM转换]仅适用于Java互操作;由于Kotlin具有适当的函数类型,因此不需要将函数自动转换为Kotlin接口的实现,因此不受支持 但是,您可以创建一个扩展方法(这样它就不会在Java中作为
管理器的方法之一可见),将给定的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的管理器
实例中不可见。在Kotlin中,listener
变量在Manager
类之外不可见,可以将其用作lambda字段
但是,getListener
和setListener
方法在Kotlin中都是可见的,并且可以访问。此外,Kotlin的lambda在转换为匿名对象时不会内联。不幸的是,Kotlin中的接口不支持SAM转换。例如,你可以读到它
现在,您可以用Java声明侦听器接口:
public interface Listener {
void onDone(String id);
}
并在Kotlin中使用它
manager.listener = Listener { println(it) }
我不知道扩展方法对Java是隐藏的。但即使是这样,我如何从Kotlin隐藏基于接口的变体?@noamtm:它们不是隐藏的,Kotlin为它们生成一个单独的Java类,并将它们作为静态方法放在内部。我的意思是,这个扩展在Java的管理器
类实例中是不可访问的,因此Java开发人员甚至不应该意识到这样的方法的存在。我不认为您可以将基于接口的变量隐藏在Kotlin的某个地方。正如我所说的,我发现它非常干净,但它仍然只是一个解决办法。@noamtm我用第二种方法编辑了我的答案。