如何使用自定义类将其转换为lambda?

时间:2019-11-16 05:02:10

标签: android kotlin lambda

我使用Kotlin并练习lambda表达。

通常,View.setOnClickListener可以转换为lambda

正常

textView.setOnClickListener(object :View.OnClickListener{
    override fun onClick(p0: View?) {

    }
})

Lambda

textView.setOnClickListener { }

然后我复制源代码并只是将函数重命名

class CustomView{

    fun setCustomOnClickListener(l: CustomOnClickListener) {
        throw RuntimeException("Stub!")
    }

}

interface CustomOnClickListener {
    fun customOnClick(var1: View?)
}

我创建了customView,但无法将其转换为lambda

      val myCustomView = CustomView()

      myCustomView.setCustomOnClickListener(object :CustomOnClickListener{

          override fun customOnClick(var1: View?) {

          }
      })

  //  can't convert to 
  //  myCustomView.setCustomOnClickListener{
  //
  //  } 

谁能解释为什么以及如何转换为lambda表达式?

谢谢!

4 个答案:

答案 0 :(得分:1)

您要问的是所谓的SAM转换(将实际的接口实现转换为lambda)。 SAM代表“单一抽象方法”。

您只能对Java接口(View.OnClickListener是)进行SAM转换。但是您的CustomOnClickListener是Kotlin界面。因此,您不能进行SAM转换。您必须使用object : CustomOnClickListener { override . . . }来实现它。您不能使用lambda。

直接从Kotlin docs

  

请注意,此功能仅适用于Java互操作。由于Kotlin具有适当的功能类型,因此无需将功能自动转换为Kotlin接口的实现,因此不受支持

如果要保持代码简洁,您可以做的是,与其创建interface CustomOnClickListener,还可以做

typealias CustomOnClickListener = (View?)->Unit

然后您的设置器功能将是相同的。这样,您的调用函数将为this.myListener(myView)

或者您甚至可以改用实验性内联类:

inline class CustomOnClickListener(val customOnClick: (View?)->Unit)

那您的传教士将是

fun setListener(listener: CustomOnClickListener) { this.listener = listener }

您的调用代码应为

listener.customOnClick(someView)

编辑:更多充实的代码:

class CustomView{
    var listener: CustomOnClickListener? = null

    fun setCustomOnClickListener(l: CustomOnClickListener) {
        listener = l
    }

}

然后您可以执行以下操作:

inline class CustomOnClickListener(val customOnClick: (View?)->Unit)

然后是您的自定义视图:

val myCustomView = CustomView()

myCustomView.setCustomOnClickListener(CustomOnClickListener({ it: View? ->
    // whatever your listener is supposed to do with the view, it goes here
}))

或者,您可以执行以下操作,而不是inline class(在Kotlin中仍被视为实验功能):

typealias CustomOnClickListener = (View?)->Unit

然后是您的自定义视图:

val myCustomView = CustomView()

myCustomView.setCustomOnClickListener { it: View? ->
    // whatever your listener is supposed to do with the view, it goes here
}

Here是一个示例。

答案 1 :(得分:0)

就像@ user1713450所说的那样,这个概念称为SAM Conversion,仅适用于Java互操作。由于Kotlin具有适当的功能类型,因此不需要将功能自动转换为Kotlin接口的实现,因此不受支持。

在上面解释您的代码:

object关键字可用于创建称为匿名对象的匿名类的对象。如果您需要创建一个对某些类或接口稍加修改而又不为其声明子类的对象,则可以使用它们。

正确的语法应为:

interface CustomOnClickListener {

fun customOnClick(var1: View?)

}

//Use the interface in your class
class CustomView{

fun setCustomOnClickListener(l: CustomOnClickListener) {
    throw RuntimeException("Stub!")

  }

}

要使用CustomView类:

val customView = CustomView()

  customView.setCustomOnClickListener(object: CustomOnClickListener{

      override fun customOnClick(var1: View?) {

      }
  })

答案 2 :(得分:0)

我已经使用 lambda 函数作为参数转换了微调器的 OnItemSelectedListener 看看我只关心 onItemSelected 方法的地方。

import android.view.View
import android.widget.AdapterView

class SelectionListener(val lis:(parent: AdapterView<*>?, view: View?, position: Int, id: Long) -> Unit) : AdapterView.OnItemSelectedListener {


  override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {

    lis(parent,view, position, id)

  }

  override fun onNothingSelected(parent: AdapterView<*>?) { }

}

现在将它附加到活动/片段中的微调器

my_spinner.onItemSelectedListener = SelectionListener { parent, view, position, id ->
//do your work after selection
}

答案 3 :(得分:0)

我认为截至发布此问题的日期,在 Kotlin 中不可能这样做。但现在它在 Kotlin 1.4 版本中可用,带有函数式接口。

这是一个如何做的例子:

// Define your interface here (note the 'fun' modifier prior to 'interface')
fun interface CustomOnClickListener {
    fun customOnClick(view: View)
}

// Call your custom interface in the form of a Lambda
myCustomView.setCustomOnClickListener { view ->
    // Implement your logic here
}

有关函数式接口的更多信息,您可以访问以下链接https://kotlinlang.org/docs/fun-interfaces.html#sam-conversions