在学java或者android的时候,或多或少会遇到一个熟悉的名词:回调函数(callback)。曾经遇到,无耐自己理解不到位,在师兄的介绍与自己翻阅资料后,有了更深一层的理解,特写此篇文章给之前与我有同样困惑的童鞋看看,希望有助大家来理解。
在android里其实回调应用得挺多的,比如常见的点击按钮调用回调函数
Button button = (Button)this.findViewById(R.id.button);
button.setOnClickListener(newButton.OnClickListener() {
//回调函数
@override
publicvoidonClick(View v) {
buttonTextView.setText("你点击了按钮");
}
});
回调函数的原理(由于上图更乱,所以用文字代替思路):
回调函数就是: 在A类中定义了一个方法,这个方法中用到了一个接口和该接口中的抽象方法,但是抽象方法没有具体的实现,需要B类去实现,B类实现该方法后,它本身不会去调用该方法,而是传递给A类,供A类去调用,这种机制就称为回调。
听起来挺呦口的,其实可以更加通俗的说,A类要做一件事,但它本身却没有做这件事的方法,只声明了一个包含此方法(未实现)的接口C给要调用它的人。但某天B类想调用A类的时候,用接口C给A类“送去了”做这件事的方法。但要明白的一点,本身接口C定义的具体方法是在A类中实现的。而当B类调用A类传来的具体的方法的时候,也就是回调,而被执行的A类传来的方法就被称为回调函数。
具体可通过一个实例来加深理解。
接口C
interface ICallback{
void callback();
}
A类里面的代码
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
B b = new B();
b.setCallback(new ICallback() {
@Override
public void callback() {
System.out.println("callback method");
}
}
);
b.doSth();
B类的代码
class B{
private ICallback callback;
public void setCallback(ICallback callback){
this.callback = callback;
}
public void doSth(){
b.callback();
}
}
总体来说,B类虽然有接口,但是接口的方法没有实现,属于空的。而A类就定义接口里面的方法,并且通过B类的某个方法,将实现的接口方法送到了B类中,后面B类就可以通过此接口来回调A中定义的方法。
那有的人就会问回调这么麻烦,为什么还要用它呢?
首先我们来设想这样一个场景,你在开发android的时候,需要用到许多个外表一模一样的对话框,每个对话框上有两个按钮,分别都为是与否。但每个对话框的是与否所执行的操作都是不同的。而现在有三个同学分别用自己的方法来解决。
甲:这不容易吗?我分别定义多个对话框类,在每个按钮的响应事件方法里写不一样的代码不就可以了嘛。
乙:甲的方法太笨了,我才不要写那么多重复的代码,这样写的话,代码写多了,可读性也差。毕竟java支持继承嘛。定义一个对话框基类,在上面定义好一样的按钮,外表样式什么都可以写在基类,到时候只要在每个按钮的响应事件里写不一样的代码或者重写响应事件,不就可以了嘛。
丙:你们两个原来都不知道用 回调函数 啊,其实你们只要定义一个接口,在接口写上回调函数而不实现它,让调用者写好,再传进来,连button.setOnClickListener(….)这些代码也可以省去。乙的方法虽然有些改进,也符合java中继承与重载的概念,但这样做会有一个不好的地方,就是容易衍生出许多的子类,代码也还是不够简洁。而且对话框的响应事件发生后,也要找到对应的子类修改,而且无法在调用者那里直接修改。
从上面的情景,我们可以看出来 回调函数 的重要性与其应用带来的可见的效率。