在 Kotlin lambda 表达式中覆盖多个接口方法
Posted
技术标签:
【中文标题】在 Kotlin lambda 表达式中覆盖多个接口方法【英文标题】:Overriding multiple interface methods in Kotlin lambda expressions 【发布时间】:2018-03-14 01:52:01 【问题描述】:假设我有一个Callbacks
接口,有两个方法onCurrentLocation
和onError
:
public interface Callbacks
void onCurrentLocation(ClientLocation location);
void onError();
以及在其构造函数中采用此接口的类,例如:
public MyLocationClient(Callbacks callbacks) ...
现在,在 Kotlin 中,我是否可以通过这种方式实例化 MyLocationClient:
val myLocationClient = MyLocationClient(
location: ClientLocation ->
updateClientLocation(location)
,
)
如果不是,为什么不呢?
我看到的行为是:当接口只有一个方法时,这个对象的构造编译得很好。但是,一旦我向Callbacks
添加更多方法,编译器就会抱怨
"类型不匹配。必需:回调!找到:(ClientLocation) -> 单位”
编辑:删除了对location
的空检查,因为它与问题无关。
【问题讨论】:
【参考方案1】:所以你在一个不是函数接口的匿名类上创建一个实例(它们只有一个方法)所以它会是这样的:
val myLocationClient = MyLocationClient(object : Callbacks
override fun onCurrentLocation(location : ClientLocation?)
location?.run updateLocation(this)
override fun onError() // should you not handle errors?
)
【讨论】:
是的,这段代码运行良好,但我试图避免使用 kotlin lambdas 的“样板”代码。事实上,这就是我的问题的要点。 我解释了为什么,你没有功能接口,这就是它在 Kotlin 中的编写方式 - 在同一匿名类中的方法实现之间使用,
在 Kotlin 中无效。如果您想创建更少的样板,将其拆分为 2 个功能接口并让构造函数接受 2 个参数,那么您的实现将起作用,或者只是在您的接口中删除 onError()
,因为无论如何您都有任何实现
哦,对不起,我没查什么是函数式接口。这在 Kotlin 文档中的任何地方吗?【参考方案2】:
你可以定义
class CallbacksImpl(private val onCurrentLocationF: (ClientLocation) -> Unit, private val onErrorF: () -> Unit) : Callbacks
override fun onCurrentLocation(location : ClientLocation) onCurrentLocationF(location)
override fun onError() onErrorF()
并使用它
MyLocationClient(CallbacksImpl(
location -> updateClientLocation(location) ,
))
它仍然有一些样板,但每个界面一次而不是每次使用一次,所以它很容易成为一个很好的权衡。
【讨论】:
【参考方案3】:我想这是一件好事,它不起作用,因为当接口有两个相同类型的函数时,你会怎么做?
public interface Callbacks
void anotherFunction(ClientLocation location);
void onCurrentLocation(ClientLocation location);
因此,我认为将其限制为 SAM(单一抽象方法)接口是一种好方法。
【讨论】:
我正在考虑将此作为公认的答案,因为据我了解,这实际上是您无法按照我的要求做的原因。【参考方案4】:interface IAnimatedRatingBar
fun setProgressImageResource(resourceId: Int)
fun setProgressImageDrawable(drawable: Drawable)
fun setSecondaryProgressImageResource(resourceId: Int)
fun setSecondaryProgressImageDrawable(drawable: Drawable)
fun startAnimate()
这对我来说很好。
【讨论】:
你能把你用来作为函数参数传递的语法包括进来吗?【参考方案5】:您可以使用 Kotlin 的高阶函数并合并接口检查此示例的两种方法
import android.location.Location
interface Callbacks
fun onCurrentLocation(location: Location)
fun onError()
现在定义一个实现回调接口的类
import android.location.Location
class MyLocationClient(private val callbackListener: (isSuccess:Boolean, location: Location?, error:String) -> Unit): Callbacks
override fun onCurrentLocation(location: Location)
callbackListener(true,location, "No Error")
override fun onError()
callbackListener(false,null, "Unable to get location")
在任何你喜欢的地方使用它
val myLocationClient = MyLocationClient isSuccess, location, error ->
if (isSuccess)
// proceed with location
else
// error occured show it to user
【讨论】:
以上是关于在 Kotlin lambda 表达式中覆盖多个接口方法的主要内容,如果未能解决你的问题,请参考以下文章
kotlin方法传入lambda表达式参数并调用invoke什么意思