java回调

一:背景

why-为什么需要回调关于什么是回调网上很多,但是很少有从为什么需要回调开始,所以下面从基本调用开始到最后为什么使用回调
1. 同步调用

A类中a()去调用B类的b()。
一个最大的问题,阻塞,在a()方法执行了2行代码在去调用b()方法,但是b()执行了耗时的操作,那么a()只能等到b()执行完,在能去执行或许的代码,产生了整个流程的阻塞。
所以这个只适合非耗时操作,也是项目中用到最多的方法。
2.异步调用

很多时候A类中a()去调用B类的b()需要耗时操作,就必须异步调用了
a()中开启一个新的线程执行b()这样,无论b()操作多长时间,都不会影响a()的正常执行,有利就有弊,这里如果b()是执行一些下载,刷新和a()没交互的方法不会有任何问题,但是如果a()需要b()提供一些参数,那么就不可以实现了。这里就需要回调了

二:回调

what-什么是回调

上图:A类中a()调用了b(),在b()执行完操作后又去调用了A类中的callback()通知最后的结果。
回调的理解:简单的说,A类中a()中调用了B类中b(),在一段时候后b()执行完操作,然后把自己结果作为一个或多个参数传递个A使用的过程。

三:写回调

how-如何写回调
1.基本版本
情况是这样的,学生小明要做一个加法,但是太笨了,不会!
就找到了小红,小红非常聪明,俗称超级计算机。
小明说“小红你帮我计算下1+1等于几,然后直接帮我写到作业本上,拜拜!”
然后小明跑了,小红在2s后做完,写出了最后结果。
ok
这就是最基本的回调。
小明(Student )告诉小红 (SuperCalculator )2个数字
小红 (SuperCalculator )计算完成后,在小明的本子上写出答案 (调用Student 的 fillBlank())

>public class Student {
    private String name = null;
    public Student(String name) {
        this.name = name;
    }
    public void callHelp(int a, int b) {
        new SuperCalculator().add(a, b, this);
    }
    public void fillBlank(int a, int b, int result) {
        System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result);
    }
}

>public class SuperCalculator {
    //只能接收单一学生类,没有扩展性
    public void add(int a, int b, Student xiaoming) {
        int result = a + b;
        xiaoming.fillBlank(a, b, result);
    }
}

>public class Test {scxda
    public statica void main(String[] args) {
        int a = 11;
        int b = 12;
        Student s = new Student("小明");
        s.callHelp(a, b);
    }
}

具体代码如上面,很简单,没毛病。但是,没有扩展性,小红现在只能为小明(Student)服务,如果老师来找小红,帮忙计算一下2+2等于几就不可以了,因为小红,只能接收单一的Student类,不接受Teacher。如何办
2.升级版本
增加一个父类,doJob,Student Teacher 都继承了doJob这个父类,这样小红可以愉快的算加法了,无论是谁只要是doJob的子类就可以找小红帮忙了。但是这是最后结果吗?不是的!

public abstract class doJob
{
    public abstract void fillBlank(int a, int b, int result);
}



public class Teacher extends doJob {
    private String name = null;

    public Teacher(String name) {
        this.name = name;
    }

    public void callHelp(int a, int b) {
        new SuperCalculator().add(a, b, this);
    }

    public void fillBlank(int a, int b, int result) {
        System.out.println(name + "要求小红计算:" + a + " + " + b + " = " + result);
    }
}



public class Student extends doJob {
    private String name = null;

    public Student(String name) {
        this.name = name;
    }

    public void callHelp(int a, int b) {
        new SuperCalculator().add(a, b, this);
    }

    public void fillBlank(int a, int b, int result) {
        System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result);
    }
}
public class SuperCalculator {
    //优扩展性,所有实现接口的类都可以传递进入
    public void add(int a, int b, doJob d) {
        int result = a + b;
        d.fillBlank(a, b, result);
    }
}
public class Test {
    public static void main(String[] args) {
        int a = 11;
        int b = 12;
        int c = 100;
        Student s = new Student("小明");
        Teacher t = new Teacher("Teacher");
        s.callHelp(a, b);
        t.callHelp(a,c);
    }
}

3.在次升级版本
几乎一样,但是有一个核心的区别接口
没错,这才是最常见的回调版本。
小明,和老师没有同一个父类,他们只有一个共同的接口 doJob
why?
接口和父类实现的效果一样,但是有几个很大的区别
1.降低耦合性,为了一个简单的加法功能,就去继承一个父类,太浪费了,java是单继承的,只能有一个父亲,为了一个功能就去叫爸爸,他浪费太奢侈了。父类和子类的亲密度太高了,这里没有这个需求(一般多个子类有一些公共的方法参数才会需要去继承同一个父类的)
2.减少暴露的数据,如果使用了一个父类,那么小红在计算的时候不仅仅回调fillBlank一个方法,还可以知道很多别的方法,例如小明的零食在哪了,老师喜欢那个小朋友了
3.为了后续的扩展:如果现在增加需求算乘法2*2,但是小红不会怎么办,都继承了一个父类,那只能去修改这个父类,新增一个方法,然后找到小王,让他帮忙计算,瞬间复杂了很多,很多没有关系的人在了一起。而且每增加一次都要修改一次,太麻烦了。
所以,这里最简单的就是接口了:说白了,接口能做的父类都能做,但是没有必要,这里只是需要一个契约!
接口就是这个契约
小红只需要吧计算好的结果给fillBlank()就可以了
小明,老师也只是需要知道fillBlank()给了什么参数就可以,别的情况,双方都不需要,也没有必要知道!

public interface doJob
{
     void fillBlank(int a, int b, int result);
}


public class Student implements doJob {
    private String name = null;

    public Student(String name) {
        this.name = name;
    }

    public void callHelp(int a, int b) {
        new SuperCalculator().add(a, b, this);
    }

    public void fillBlank(int a, int b, int result) {
        System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result);
    }
}

public class Teacher implements doJob {
    private String name = null;

    public Teacher(String name) {
        this.name = name;
    }

    public void callHelp(int a, int b) {
        new SuperCalculator().add(a, b, this);
    }

    public void fillBlank(int a, int b, int result) {
        System.out.println(name + "要求小红计算:" + a + " + " + b + " = " + result);
    }
}

public class SuperCalculator {
    //优扩展性,所有实现接口的类都可以传递进入
    public void add(int a, int b, doJob d) {
        int result = a + b;
        d.fillBlank(a, b, result);
    }
}



public class Test {
    public static void main(String[] args) {
        int a = 11;
        int b = 12;
        int c = 100;
        Student s = new Student("小明");
        Teacher t = new Teacher("Teacher");
        s.callHelp(a, b);
        t.callHelp(a,c);
    }
}

四:Android中的应用

回调应用非常多,android中最常见的一个应用就是各种点击事件,只要有交互的界面,都回用到View的回调。
核心都是一样onClick
1系统view内部增加一个OnClickListener接口包含一个 onClick方法。
2 定义回调接口的成员变量
public OnClickListener mOnClickListener;
3view中增加一个setOnClickListener() 设置回调接口对象成员变量
4外部的activity需要实现点击效果的控件,去调用setOnClickListener方法(所有控件最终的父类View,所以全部控件都是具有setOnClickListener方法),需要一个参数View中定义接口的实现,为了方便一般都是使用匿名内部类了。
5最后执行,在用户点击一个控件后,最终会执行performClick方法,执行mOnClickListener的onClick方法。
android中接口的好处,假设有2个button,1号点击后去刷新界面,2号点击后去下载内容。这些系统是不知道的,系统只会通知什么时候点击了,点击后的操作就是具体程序员完成了,各司其职,降低耦合度。
这个流程完成,下面是简化后的源码,看明白后对接口的理解可以更上一层了。

public class ViewT {
    /*
     * 定义回调接口的成员变量
     */
    public OnClickListener mOnClickListener;


    /**
     * 声明回调接口
     * Interface definition for a callback to be invoked when a view is clicked.
     */
    public interface OnClickListener {
        /**
         * Called when a view has been clicked.
         *
         * @param v The view that was clicked.
         */
        void onClick(ViewT v);
    }


    /**
     * 设置回调接口对象成员变量
     * Register a callback to be invoked when this view is clicked. If this view is not
     * clickable, it becomes clickable.
     *
     * @param l The callback that will run
     */
    public void setOnClickListener(OnClickListener l) {
        mOnClickListener = l;

    }

    /**
     * 调用回调接口对象中的方法
     * Call this view's OnClickListener, if it is defined.  Performs all normal
     * actions associated with clicking: reporting accessibility event, playing
     * a sound, etc.
     *
     * @return True there was an assigned OnClickListener that was called, false
     * otherwise is returned.
     */
    public boolean performClick() {
        mOnClickListener.onClick(this);
        return true;
    }


}

 //这里就是我们一般写的方法了,写一个匿名内部类实现接口,在系统调用onClick方法时候接受到消息在处理了
       ttview.setOnClickListener(new ViewT.OnClickListener() {

           @Override
           public void onClick(ViewT v) {

               //接受到 模拟的ViewT对象,可以做处理了
           }
       });

五:总结

这就是回调从无到有到强大的过程,这里只是写了一部分,太多例子文章都是最后一步。
很长时间都想不明白为什么要这样,最近收集不少文章整理后发现,要从根上面理解一个概念才能更好的学习理解了。
参考文章:
http://www.importnew.com/19301.html
http://www.cnblogs.com/xrq730/p/6424471.html
http://www.jianshu.com/p/3f86b7949f20

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值