0

今天,我们细说回调

 2 years ago
source link: http://www.androidchina.net/10495.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
今天,我们细说回调 – Android开发中文站

苏格拉底曾说过:“不懂回调的程序员不是一个好厨子”。

但对很多刚入行的朋友来说,回调确实又是一个不明觉厉的东西,理解起来稍稍有一点摸不着头脑。那么今天,笔者就以最浅显通俗的文字,带大家一起揭开回调神秘的面纱

一、回调到底是个啥?

根据《Java核心技术 第八版》中对回调的定义,回调(callback)是一种常见的程序设计模式。在这种模式中,可以指出某个特定事件发生时应该采取的动作。

啥意思?举个例子,今天你上班上到一半的时候,老板突然跑过来说:“xxx,去把办公室地扫了,扫干净了给我说一下。”好了,然后你现在自愿去扫地。扫了半个小时终于整完了,这个时候你马上跑去办公室给老板报告:“x总,地都扫干净了!”OK,你跑去给领导报告的这个动作就叫做“回调”。

再举个程序之中运用回调的例子?

OK,对Android程序员来说,我想就算你不知道回调,你也一定知道View的点击事件,点击事件就完全符合标准的回调定义“指出某个特定事件发生时应该采取的动作”。那么我们一起来看看点击事件长什么样子

view.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v) {
        //do something
    }
});

这是一个点击事件的常见写法,在onClick()方法里面实现view被点击时需要执行的逻辑即可。可是,这个onClickListener()是个啥?setOnclickListener()又是个啥?看官别急,且听我娓娓道来。

二、那我怎么写一个回调?

public class Coder{

    //声明回调对象
    private void SweepFloorListener listener;

    //定义回调接口
    interface SweepFloorListener{
        void onFinish(String str);
    }

    //回调对象的实例化 
    public void setSweepFloorListener(SweepFloorListener listener){
        this.listener = listener;
    }

    private void fun(){
        //执行回调方法
        listener.onFinish("扫完啦!");    
    }
}


public class Boss{

    private Coder coder = new Coder()

    private void fun(){
        coder.setSweepFloorListener(new Coder.SweepFloorListener(){
            @Override
            public void onFinish(String str){
                //扫完地了
                doSomething(str)
            }
        });
    }
}

OK,这样我们就实现了一个简单的回调。

仔细看,coder.setSweepFloorListener()是不是和我们上面的点击事件view.setOnclickListener()长得一模一样?一样就对了

现在我们来逐一分析回调的组成。

  1. 回调是由接口实现的,所以我们首先要写一个接口SweepFloorListener,接口里面要定义一些方法。啥方法?就是你想要在回调的时候执行的方法。比如说老板要你扫完地了告诉他,那你就要定义一个onFinish()方法表示扫完地了执行这个方法。
  2. 声明一个回调的对象。
  3. 要写一个set方法来实现对回调对象的实例化。那么为什么要有这个方法?我自己new对象不行吗?还真不行,因为今天可能是张老板叫你扫地,明天可能是李老板叫你,后天又可能是王老板,那你怎么知道扫完了该给谁汇报?所以我们才需要通过set方法传过来对象,这样我们才知道:“哦,今天扫完了该给李老板汇报”。
  4. 执行回调方法。就是在你扫完地的时候执行listener.onFinish()方法
  5. 接收回调。这一步是站在老板的角度:今天心情好,随机抓一个程序员扫地。当他扫完的了需要告诉我地都扫完了,这个时候就给他安一个回调,具体就是执行coder.setSweepFloorListener()方法,给这个方法传入一个回调接口,就是Coder.SetSweepFloorListener()参数,然后重写这个回调接口里面的onFinish()方法,当onFinish()方法执行的时候,就表示地已经扫完了,扫地的程序员已经在通知我了。

三、那有没有更优雅的写法?

1.Lambda表达式

我们可以使用Lambda表达式来使代码看起来更优雅,其实质是没有变的,如点击事件

view.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v) {
        finish();
    }
});

可以用Lambda表达式改写

view.setOnClickListener(v -> finish());

这里的v表示onClick(View v)的参数v

coder.setSweepFloorListener(new Coder.SweepFloorListener(){
    @Override
    public void onFinish(String str){
        doSomething(str);    
    }
});

可以改写为

coder.setSweepFloorListener(str -> doSomething(str));

这里的str表示onFinish(String str)的参数

怎么样,看起来是不是优雅多了?

那还有没有更优雅的?

2.Kotlin高阶函数实现回调

作为一个Android开发人员,怎么能不会Kotlin呢?Kotlin的高阶函数特性可以让我们更优雅的实现回调。

对Coder和Boss类进行改写

class Coder(){

    private lateinit var onFinish: (String) -> Unit 

    fun setSweepFloorListener(onFinish:(String) -> Unit){
        this.onFinish = onFinish    
    }

    private fun sweepFloor(){
        //执行回调方法
        onFinish("扫完啦!")
    }
}


class Boss(){

    private coder = Coder()

    private fun test(){
        coder.setSweepFloorListener{ str -> doSomething(str) }    
    }
}

这就很优雅了,我们直接干掉了回调接口SweepFloorListener()。

卧槽,还可以这么干?

所谓高阶函数,就是指可以接收函数作为入参的函数,嗯……好像听起来跟Lambda表达式是一个东西。那么我们这里具体是怎么运用了高阶函数来实现的回调呢?

  1. 我们首先定义了一个变量onFinish,这个变量本身就是一个函数,(String) -> Unit 表示这个函数的入参为一个String,没有返回值
  2. 然后写了一个setSweepFloorListener()方法来为这个变量进行实例化
  3. 需要的地方直接调用onFinish(str)方法即可
  4. 在另一个类里面进行回调coder.setSweepFloorListener{ str -> doSomething(str) }
    OK,这样我们就使用Kotlin优雅地实现了回调。

今天总结了回调的几种不同实现方式,希望能给到初级的朋友们一些帮助。

有不对之处还望各位同僚雅正。

参考资料:

  1. 《Java核心技术 第八版》
  2. 《解密Kotlin编程原理》

作者:机智的张尼玛
链接:https://juejin.im/post/5e4cdaa3e51d4526e807e96e


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK