Java Kotlin函数参数:如何定义一个可以有一个尾随lambda或接口作为参数的函数?
我发现了两个类似的代码:Java Kotlin函数参数:如何定义一个可以有一个尾随lambda或接口作为参数的函数?,java,android,kotlin,Java,Android,Kotlin,我发现了两个类似的代码: binding.playButton.setOnClickListener ( Navigation.createNavigateOnClickListener(R.id.action_titleFragment_to_gameFragment) ) android视图类中的Java代码: public void setOnClickListener(@Nullable OnClickListener l) { if (!isClick
binding.playButton.setOnClickListener (
Navigation.createNavigateOnClickListener(R.id.action_titleFragment_to_gameFragment)
)
android视图类中的Java代码:
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
问题是:我如何创建这样的函数,在这里我可以使用后面的lambda或interface作为参数?
我发现类型不匹配
interface One {
fun a(): Int
}
class OneImp : One {
override fun a(): Int {
return 4
}
}
fun test(one: One) {
val a = one
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val a = OneImp()
test (a) //works fine
test {
a //error
}
}
错误:
Type mismatch.
Required:
TitleFragment.One
Found:
() → TitleFragment.OneImp
更新:
在回答了@Jenea Vranceanu之后,我在测试SAM时发现了错误(我使用了kotlin文件中的接口,而所有代码都应该是java)。
解决方案将是:(在kotlinv v1.4发布之前)
创建java文件:
public class Mine {
public interface One {
int a();
}
public class OneImpl implements One {
@Override
public int a() {
return 4;
}
}
public void test(One one) {}
}
然后我可以使用函数参数和lambda。现在在kotlin文件中:
Mine().test {4}
val b = Mine().OneImpl()
Mine().test (b)
注:如果他将其添加到他的答案中,我将从这里删除If。您误解了
binding.playButton.setOnClickListener在每种情况下的工作方式
在第一个示例中,导航
组件创建视图。OnClickListener
,该视图被传递到设置OnClickListener
(注意括号或圆括号):
在Java中,它看起来几乎相同:
binding.getPlayButton().setOnClickListener (
Navigation.createNavigateOnClickListener(R.id.action_titleFragment_to_gameFragment)
)
第二个例子的工作原理稍有不同。首先,使用大括号创建View.OnClickListener
,并定义此视图的主体。OnClickListener
方法onClick(视图)
:
在大括号内有对单击视图的引用:
binding.playButton.setOnClickListener {
it.context // `it` is the clicked view
}
// It is the same as
binding.playButton.setOnClickListener { view ->
view.context
}
为什么它完全不起作用?
这种类型的定义匿名类只能在和视图中使用。OnClickListener
是Java中定义的SAM类Kotlin SAM类/接口尚不支持此功能。
以书面形式:
val a = OneImp()
test {
a //error
}
您假设test
函数声明如下所示:
fun test(one: () -> One) {
val a = one()
}
请注意,在第二个示例中,问题顶部的Navigation.findNavController(it.navigate
不会创建View.OnClickListener
对象大括号创建此对象,由于此接口只有一个抽象方法,因此无法写入此方法签名,因此大括号内声明的所有内容直接进入void onClick(View View)
方法
更新(正式文件)
。这是官方文件,底部写着:
。。。请注意,此功能仅适用于Java互操作;由于Kotlin具有适当的函数类型,因此不需要将函数自动转换为Kotlin接口的实现,因此不受支持
因此,Kotlin接口永远不支持它,因为不需要它。看来我对“山姆永远不会得到支持”的看法是错误的。这将是,但它还没有提供。Kotlin类的SAM转换将从Kotlin 1.4开始提供,Kotlin 1.4现在是一个候选版本
用解决方案更新
最初未添加替代解决方案。提问者礼貌地要求添加下一个代码以完成回答。谢谢
我已经更新了您的问题标题,使其成为一个问题,如果您对我的更改不满意,请随意编辑:)简单地说,test{…}
与test({…})
相同,lambda作为参数传递,而不是One
。看,山姆很难理解…:((Kotlin 1.4支持对Kotlin接口进行SAM转换,该版本目前处于候选发布阶段。太好了!感谢您指出这一点。我将更新我的答案。@JeneaVranceanu,感谢您的回答,尽管您没有回答如何做的问题。我在java类中绑定了该转换,但我使用了Kotlin文件中的接口,这是我的问题。)因此,答案将是创建一个新的.java文件,代码为``public class Mine{public interface One{int a();}public class OneImpl实现一个{@Override public int a(){return 4;}}}public void test(One){}```在这之后,IDE提供了lambda提示。请您将其放入您的答案中,使其完整。
binding.playButton.setOnClickListener {
it.context // `it` is the clicked view
}
// It is the same as
binding.playButton.setOnClickListener { view ->
view.context
}
val a = OneImp()
test {
a //error
}
fun test(one: () -> One) {
val a = one()
}
public class Mine {
public interface One {
int a();
}
public class OneImpl implements One {
@Override public int a() { return 4; }
}
public void test(One one) {}
}