我如何在Kotlin中使用回调函数?

86

我有一个View和一个CircleShape,应该在这个View中显示toast。我在主Activity中使用它。

这是我的接口

interface OnClickListenerInterface {
  fun onClick()
}

它是CircleShape(在我的xml中是View)并且是我的View中的listener。我想在我的Activity中实现OnClick。

 var listener: OnClickListenerInterface? = null

 mCircleShape.setOnClickListener(View.OnClickListener {
      if (listener == null) return@OnClickListener
      listener!!.onClick()
    })

我知道,在 Kotlin 中,getter 和 setter 是自动泛型的,但如果它是私有的,我该如何设置监听器呢?这是来自我的 Activity 的代码,但它不起作用。

CircleShape.listener  = object :OnClickListenerInterface{
      override fun onClick() {
        ToastUtils.showSuccessMessage(getContext(),"pressed")
      }
    }

我应该如何在Kotlin中使用Callback和OnClickListener?


它不起作用 - 有什么错误? - Salem
监听器未处于活动状态。 - manwhotrycoding
1
帮助我实现了回调。object:OnClickListenerInterface 部分对我来说是未知的。谢谢。 - vyi
以下是一些解决方案:https://stackoverflow.com/a/56608847/753632 - Johann
8个回答

103

使用lambda表达式可以更简单地解决问题。

CircleShape.kt 中,声明一个lambda函数。

var listener: (()->Unit)? = null
...
// When you want to invoke the listener
listener?.invoke()

在您的 Activity 内部

mCircleShape.listener = {
    // Do something when you observed a call
}

这应该被接受的答案 - Dmitry Guselnikov

69

像这样定义一个函数:

  fun performWork(param1: String, myCallback: (result: String?) -> Unit) {
    // perform some network work

    // on network finished
    myCallback.invoke("result from network")
  }

使用方法如下:

  performWork("http://..."){ result ->
  //use result
  }

1
你可以直接调用 myCallback("结果字符串") - Konstantin Konopko

41

在 CircleShape.kt 中。

private listener OnClickListenerInterface? = null
...
fun setOnClickListener(listener: OnClickListenerInterface) {
    this.listener = listener
}

你的活动

mCircleShape.setOnClickListener(object: CircleShape.OnClickListenerInterface {
    override fun onClick() {
      // Do something here
    }
})

如果你要使用lambda表达式,可以使用函数类型。以下是在CirclesShapt.kt中的示例:

fun setOnClickListener(listener: () -> Unit){
   listener() // or you could use optional if the lister is nullable "listener?.invoke()"
}

所以在实际活动中看起来是这样的。

mCircleShape.setOnClickListener {
  // Do something here
}

5
你的第二个解决方案没有展示CirclesShape.kt中setOnclickListener应该如何调用监听器。 - Johann

9

为了使用Kotlin回调函数,我在我的API调用中使用它们来处理成功或失败的情况。

创建一个枚举类来表示状态。

enum class APIState(val result: Boolean) {
SUCCESS(true),
FAILURE(false)}

在函数中使用回调。
 private fun fetchFeesList(studentID:String,call:(APIState)->Unit){
 ... do stuff here , and use call(APIState.SUCCESS) or call(APIState.FAILURE) }

调用 fetchFeesList 函数时,请以如下方式调用:
fetchFeesList(studentID){
        val res = it.result
        if(res){
            toast("success")
        }else {
            toast("failure")
        }
    }

使用Anko库的toast("message")方法,请前往GitHub下载:- https://github.com/Kotlin/anko

5

我一直在绝望地寻找类似于Java接口的Kotlin解决方案,直到我发现了上面提供的建议。尝试了所有这些建议后,我无法得出适合我的情况的可工作解决方案。

这导致了我自己的实现方式,根据我的使用情况完美地工作,因此我想分享一下,尽管它可能不是最完美的方式,在此提前道歉。

步骤:

  • 1. 定义你的接口:
interface OnClickListenerInterface {
    fun onClick()
}
  • 2. 在将触发"onClick"回调的类中,即您的情况下的"CircleShape"中:

创建一个可为空的变量。

var listener: OnClickListenerInterface? = null

声明一个函数来初始化上面的变量。

fun initOnClickInterface(listener: OnClickListenerInterface){
        this.listener = listener
    }

在希望触发 "onClick" 回调的位置:
mCircleShape.setOnClickListener(View.OnClickListener {
      if (listener == null) return@OnClickListener
      listener?.onClick() // Trigger the call back
    })
  • 3. 在你需要接收"onClick"回调的活动中:

让该活动实现OnClickListenerInterface接口,然后创建一个CircleShape类的对象。

class Activity : AppCompatActivity(), OnClickListenerInterface {
    val mCircleShape = CircleShape()
    // ...other stuff

在这个活动的 onCreate 函数内,使用 CircleShape 类中创建的 initOnClickInterface 函数初始化您的接口。
mCircleShape.initOnClickListenerInterface(this)

最后,在活动中添加以下代码,通过覆盖我们接口的 onClick 方法来完成。

override fun onClick() {
        // Callback received successfully. Do your stuff here
    }

以上步骤适用于我。

正如我所说,如果我的编码出现任何问题,我也是一个学习者。

干杯!


1

已测试。这个可行。

// Define interface
interface MyCallback {
    fun success(param: String)
    fun fail(param: String)
}

fun functionHasCallback(param: Boolean, callback: MyCallback) {
    // do somthing
    if (ok) {
        callback.success("value")
    } else {
        callback.fail("value")
    }
}

// Call function
functionHasCallback(
    boolParam, 
    object: MyCallback {
        override fun success(param: String) {
            // Your code here
        }

        override fun fail(param: String) {
            // Your code here
        }
    }
)

1

你尝试使用过lambda表达式吗?例如在你的情况下:

mCircleShape.setOnClickListener( 
    { _ -> ToastUtils.showSuccessMessage(context,"pressed") }
)

或者如果你想让它更符合 Kotlin 风格:

mCircleShape.listener = ( 
    { _ -> ToastUtils.showSuccessMessage(context,"pressed") }
)

0
首先,您需要删除此代码:
mCircleShape.setOnClickListener(View.OnClickListener {
      if (listener == null) return@OnClickListener
      listener!!.onClick()
    })

因为listener一开始总是为空,你的代码只会一直返回。

var listener: OnClickListenerInterface? = null已经是公共的(这是Kotlin中的默认访问级别)。所以当需要时,你可以在你的活动中设置它。使用listener?.onClick()调用来从你的CircleShape触发它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接