回调的介绍以及使用(以kotlin为例)

回调的介绍以及使用(以kotlin为例)

什么是回调?

先来看一下维基百科的解释:

在计算机程序设计中,回调函数,或简称回调(Callback 即call then back 被主函数调用运算后会返回主函数),是指通过参数将函数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。

嗯。每个人我都认识,为什么连在一起就不认识了呢…
算了算了,先不管这个定义了,直接从案例出发吧,这样更容易理解一些。

案例

假设现在有这样一个场景,我需要给用户展示一个信息提示板,提示板里面需要填充信息。但是填充的信息需要经过一系列处理才能生成,所以这个处理的时间会很长。如果我直接让程序线性执行下去,那么用户要等很久才会看到这个提示板,并且在等待的过程中程序会卡顿,用户不能执行其他操作。于是,用户就摔了他的键盘(暴躁德国boy)。

有没有什么更好的解决办法呢?还是有的,我可以将面板的创建和数据处理的过程分离开,另开一个线程用于处理数据,这样用户就可以先看到面板界面,同时程序也不会卡顿。用户的键盘终于保住了。

但这样又会出现一个问题,由于信息处理是异步执行的,当信息处理完毕后我要怎么将数据填充到提示面板里呢?我们知道程序都是顺序执行的,如果只是按照顺序执行的逻辑,我们将没办法获取到处理后的数据。这时候,回调给我们提供了一种解决方案。

回调的基本构成

回调一般由三部分组成,分别为回调接口,回调的调用,以及回调的实现。还是从刚才的例子出发,使用回调前,我们必须要定义一个接口,接口如下:

interface CallBack{
    fun action(name: String)
}

之后,我们需要定义一个调用类,按照案例的描述,我们将这个类定义为Panel。

class Panel(){
    var panelMsg = "null"
    lateinit var dataDeal: CallBack

    fun createPanel() {
        println("create panel, initial val is ${panelMsg}")
    }

    @JvmName("setDataDeal1")
    fun setDataDeal(dataDeal: CallBack){
        // 这里表示我要提前调用一个回调,但是并没有对回调做定义
        this.dataDeal = dataDeal
        val thread = Thread{
            this.dataDeal.action("resultStr")
        }
        thread.start()
    }
}

最后,我们需要在程序运行的时候定义这个回调的实现:

fun main(){
    val panel = Panel()
    panel.createPanel()
    panel.setDataDeal(object : CallBack {
        override fun action(name: String) {
            TimeUnit.SECONDS.sleep(5)
            panel.panelMsg = name
            println("new panel val is ${panel.panelMsg}")
        }
    })
}

有了这三部分,一个回调的功能就算是完成了,我再贴一下完整代码:

import java.util.concurrent.TimeUnit

interface CallBack{
    fun action(name: String)
}

class Panel(){
    var panelMsg = "null"
    lateinit var dataDeal: CallBack

    fun createPanel() {
        println("create panel, initial val is ${panelMsg}")
    }

    @JvmName("setDataDeal1")
    fun setDataDeal(dataDeal: CallBack){
        // 这里表示我要提前调用一个回调,但是并没有对回调做定义
        this.dataDeal = dataDeal
        val thread = Thread{
            this.dataDeal.action("resultStr")
        }
        thread.start()
    }
}

fun main(){
    val panel = Panel()
    panel.createPanel()
    panel.setDataDeal(object : CallBack {
        override fun action(name: String) {
            TimeUnit.SECONDS.sleep(5)
            panel.panelMsg = name
            println("new panel val is ${panel.panelMsg}")
        }
    })
}

通过对上述代码的分析,我们不难看出,其实回调的内核就是将函数的使用过程和函数的实现过程分离开来。在代码中,我可以先提前使用对应的方法,帮助我们在逻辑上实现一个功能。而真正需要使用的时候,我们才需要实现回调的内容,这样就做到了异步通信的功能。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值