【问题标题】:Overriding multiple interface methods in Kotlin lambda expressions在 Kotlin lambda 表达式中覆盖多个接口方法
【发布时间】:2018-03-14 01:52:01
【问题描述】:

假设我有一个Callbacks 接口,有两个方法onCurrentLocationonError

    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 的空检查,因为它与问题无关。

【问题讨论】:

    标签: android lambda interface kotlin


    【解决方案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
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多