首先实现一个简单的回调函数,回调函数是通过函数指针调用的函数,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说是回调函数。回调函数不是由该函数的实现方直接调用的,而是在特定的时间或田间发生时有另外的一方调用的,用于对改时间或条件进行响应。说的很抽象,我也不懂。
下面来举个简单的列子,看了这个列子你就懂了,网上有很多都是用的这个列子。假设有个老板顾另一位员工做事情,但是事情的进展或者说事情什么时候做完老板和员工都不知道。这时老板有其他的事情要做,不可能一直看着员工把活干完,那么怎么办呢?这是老板和员工就商量,让员工干完活后通知老板,通知方式肯定是由老板说了算。这样老板就可以开心的离开了。
就是这么个列子,用回调机制怎么来实现呢?
第一我们要定义一个回调接口,里面要有回调方法,
public interface CallBackInterface {
public void call(String str); //一个类实现方法,决定类之间联系的方式。另一个类声明接口并调用方法通知实现接口方法类
}
第二就是让老板去实现这个回调接口,并实现方法,也就是员工干完事情采用什么样的方式通知来办是由来办实现这个方法来决定的。
public class Boos implements CallBackInterface{
@Override
public void call(String str) {
Log.v("test", "Boss收到消息"); //老板讲员工传来的信息打印出来
}
}
第三就是员工类了,员工类里有回调接口的实例,这个实例需要从外部传入,传入方法叫做注册回调接口。这样当员工做完事情之后就可以通过这个实例来调用老板实现类的方法通知老板了。注册回调接口有很多种方式。只要能传入就可以了。这里有两种方式。
public class Work {
public CallBackInterface mcallback; // 声明接口类,以便于另一个类实现通信
public void setCallBack(CallBackInterface callBackInterface){ //注册接口实例
this.mcallback = callBackInterface;
}
public void doSomeThing(){ // 员工开始做工作,通过接口通知老板
for (int i = 0; i < 10; i++) {
Log.v("test", "员工工作"+i);
}
mcallback.call("工作完成了,通知老板"); //通过接口方法 来与另一个类进行通信
}
public void setOnCall(CallBackInterface callBackInterface){//注册回调接口实例
this.mcallback = callBackInterface;
for (int i = 0; i < 10; i++) {
Log.v("test", "员工工作"+i);
}
mcallback.call("工作完成了,通知老板");
}
}
注册回调接口还可以通过员工的构造方法传入。当员工做完事情之后,就是通过注册的这个接口实例调用老板类实现的方法来通知老板的。
最后看看测试类。
public class TestCallBackActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//方式一
Boos boss = new Boos();
Work work = new Work();
work.setCallBack(boss); //调用对应方法。参数为接口实现类 这样两个类就建立联系了
work.doSomeThing(); //消息是在这个方法里面发送的
//方式二
new Work().setOnCall(new CallBackInterface() {
@Override
public void call(String str) {
Log.v("test", "Boss收到消息 匿名内部类方式:" +str);
}
});
}
}
最后看看测试结果的打印日志:
11-19 13:47:21.480: V/test(29352): 员工工作0
11-19 13:47:21.480: V/test(29352): 员工工作1
11-19 13:47:21.484: V/test(29352): 员工工作2
11-19 13:47:21.492: V/test(29352): 员工工作3
11-19 13:47:21.496: V/test(29352): 员工工作4
11-19 13:47:21.496: V/test(29352): 员工工作5
11-19 13:47:21.500: V/test(29352): 员工工作6
11-19 13:47:21.500: V/test(29352): 员工工作7
11-19 13:47:21.504: V/test(29352): 员工工作8
11-19 13:47:21.504: V/test(29352): 员工工作9
11-19 13:47:21.504: V/test(29352): Boss收到消息:工作完成了,通知老板
11-19 13:47:21.504: V/test(29352): ++++++++++++++++++++++++++
11-19 13:47:21.508: V/test(29352): 员工工作0
11-19 13:47:21.508: V/test(29352): 员工工作1
11-19 13:47:21.508: V/test(29352): 员工工作2
11-19 13:47:21.508: V/test(29352): 员工工作3
11-19 13:47:21.508: V/test(29352): 员工工作4
11-19 13:47:21.512: V/test(29352): 员工工作5
11-19 13:47:21.512: V/test(29352): 员工工作6
11-19 13:47:21.512: V/test(29352): 员工工作7
11-19 13:47:21.512: V/test(29352): 员工工作8
11-19 13:47:21.512: V/test(29352): 员工工作9
11-19 13:47:21.516: V/test(29352): Boss收到消息 匿名内部类方式:工作完成了,通知老板
从日志中不难看出,当员工做完工作后去通过接口实例去回调了老板类中实现的回调接口方法。 而且还是先了两个类之间的参数传递。
第二种注册接口实例的方式看起来是不是很像Android中的注册事件监听,其实在Android中的很多事件监听都是通过回调机制来实现的。
1.定义接口
public interface OnClickListener {
public void OnClick(Button b);
}
2. 定义Button
public class Button {
OnClickListener listener;
public void click() {
listener.OnClick(this);
}
public void setOnClickListener(OnClickListener listener) {
this.listener = listener;
}
}
3. 将接口对象OnClickListener 赋给 Button的接口成员
public class Activity {
public Activity() {
}
public static void main(String[] args) {
Button button = new Button();
button.setOnClickListener(new OnClickListener(){
@Override
public void OnClick(Button b) {
System.out.println("clicked");
}
});
button.click(); //user click,System call button.click();
}
}