Kotlin SAM 转换不适用于具有两个参数的函数
Kotlin SAM conversion doesn't work for function with two arguments
我正在学习 Kotlin 并尝试在其中使用 LiveData。由于 LiveData 库是用 Java 编写的,Kotlin 应该支持 SAM 转换。
LiveData
class has method observe
with two arguments, Observer
and LifecycleOwner
:
void observe (LifecycleOwner owner, Observer<T> observer)
两者都是单一方法的接口。当我对两个参数使用 SAM lambda 时,它工作正常:
val liveData = MutableLiveData<Int>()
liveData.observe({ lifecycleOwner.lifecycle }, { invokeMyMethod(it) })
当我提供特定类型的对象和 SAM lambda 时它也有效 (Observer
):
val liveData = MutableLiveData<Int>()
liveData.observe(lifecycleOwner, Observer { invokeMyMethod(it) })
但是,当我尝试对一个参数使用对象,对另一个参数使用无类型的 SAM lambda 时:
val liveData = MutableLiveData<Int>()
liveData.observe(lifecycleOwner, { invokeMyMethod(it) })
它给我编译错误。但是为什么我不能写这样的代码呢?这正是我想要的,紧凑且没有样板代码。 LiveData
中只有一个observe
方法,为什么我必须指定lambda的类型?
编译器产生这样的错误:
Type mismatch. Required: Observer!>, Found: () → Unit
小更新,我刚刚检查了这个组合,它也不起作用:
val liveData = MutableLiveData<Int>()
liveData.observe({ lifecycleOwner.lifecycle }, Observer { invokeMyMethod(it) })
所以当两个参数都是 SAM lambda 时它有效,但当一个是 SAM lambda 而另一个是指定类型的 SAM lambda 时它不起作用。在这种情况下,编译器也会给出相同的 Type mismatch
错误。
你的观察似乎是正确的,但我无法回答你为什么。
我们看到 Kotlin 看到 LifecycleOwner, Observer
或 () -> Lifecycle, (Int?) -> Unit
。至于为什么你看不到每个组合,只有使用 Kotlin 的人才知道!
不过,我可以为您提供解决方法。
将此扩展功能添加到您的项目中:
inline fun <T> LiveData<T>.observe(lifecycleOwner: LifecycleOwner, crossinline observer: (T?) -> Unit) {
observe(lifecycleOwner, Observer { observer(it) })
}
现在它会神奇地工作(假设您的扩展函数已导入)!
fun blah() {
liveData.observe(lifecycleOwner) { // <-- trailing lambda
invokeMyMethod(it)
}
}
这是https://youtrack.jetbrains.com/issue/KT-14984. And according to that, it should finally be fixed in Kotlin 1.3, but the type inference changes required are opt-in for now and need to be enabled explicitly: https://discuss.kotlinlang.org/t/new-type-inference-in-kotlin-1-3-0-rc-190/9914/2
好消息是 kotlin 现在可以正确处理具有多个参数的函数的 SAM 转换。
observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
只需更新到最新的实时数据版本,他们还deprecated当前观察
示例:
livedata.observe(viewLifecycleOwner, ::bindData)
private fun bindData(unit: Unit) { }
我正在学习 Kotlin 并尝试在其中使用 LiveData。由于 LiveData 库是用 Java 编写的,Kotlin 应该支持 SAM 转换。
LiveData
class has method observe
with two arguments, Observer
and LifecycleOwner
:
void observe (LifecycleOwner owner, Observer<T> observer)
两者都是单一方法的接口。当我对两个参数使用 SAM lambda 时,它工作正常:
val liveData = MutableLiveData<Int>()
liveData.observe({ lifecycleOwner.lifecycle }, { invokeMyMethod(it) })
当我提供特定类型的对象和 SAM lambda 时它也有效 (Observer
):
val liveData = MutableLiveData<Int>()
liveData.observe(lifecycleOwner, Observer { invokeMyMethod(it) })
但是,当我尝试对一个参数使用对象,对另一个参数使用无类型的 SAM lambda 时:
val liveData = MutableLiveData<Int>()
liveData.observe(lifecycleOwner, { invokeMyMethod(it) })
它给我编译错误。但是为什么我不能写这样的代码呢?这正是我想要的,紧凑且没有样板代码。 LiveData
中只有一个observe
方法,为什么我必须指定lambda的类型?
编译器产生这样的错误:
Type mismatch. Required: Observer!>, Found: () → Unit
小更新,我刚刚检查了这个组合,它也不起作用:
val liveData = MutableLiveData<Int>()
liveData.observe({ lifecycleOwner.lifecycle }, Observer { invokeMyMethod(it) })
所以当两个参数都是 SAM lambda 时它有效,但当一个是 SAM lambda 而另一个是指定类型的 SAM lambda 时它不起作用。在这种情况下,编译器也会给出相同的 Type mismatch
错误。
你的观察似乎是正确的,但我无法回答你为什么。
我们看到 Kotlin 看到 LifecycleOwner, Observer
或 () -> Lifecycle, (Int?) -> Unit
。至于为什么你看不到每个组合,只有使用 Kotlin 的人才知道!
不过,我可以为您提供解决方法。
将此扩展功能添加到您的项目中:
inline fun <T> LiveData<T>.observe(lifecycleOwner: LifecycleOwner, crossinline observer: (T?) -> Unit) {
observe(lifecycleOwner, Observer { observer(it) })
}
现在它会神奇地工作(假设您的扩展函数已导入)!
fun blah() {
liveData.observe(lifecycleOwner) { // <-- trailing lambda
invokeMyMethod(it)
}
}
这是https://youtrack.jetbrains.com/issue/KT-14984. And according to that, it should finally be fixed in Kotlin 1.3, but the type inference changes required are opt-in for now and need to be enabled explicitly: https://discuss.kotlinlang.org/t/new-type-inference-in-kotlin-1-3-0-rc-190/9914/2
好消息是 kotlin 现在可以正确处理具有多个参数的函数的 SAM 转换。
observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
只需更新到最新的实时数据版本,他们还deprecated当前观察
示例:
livedata.observe(viewLifecycleOwner, ::bindData)
private fun bindData(unit: Unit) { }