00、What - 什么是回调 ?
回调机制最早应用于框架编程技术,是指在编写框架/类库(比如Android底层实现)时,需要上层模块提供具体实现的代码的机制;上层模块所提供的这种代码则称为回调函数。说人话,请看图一。
【注意】文中提及框架/类库只是为了形象化说明是底层实现;同样地,App也只是为了形象划说明是上层实现。回调技术不仅仅用于框架设计中,其本质上是分层思想,同样适用于我们业务代码的实现。
01、How - 回调的极简实现步骤
要实现回调技术,一般由以下四个步骤组成:
- 定义回调接口:先定义一个回调接口,该接口里面声明了回调函数;一般由框架提供。
- 定义回调对象:上层程序App实现该接口,并在回调函数中实现了具体的功能;由App实现。
- 注册回调对象:底层框架添加回调对象;一般由App调用框架的函数实现。
- 调用回调函数:框架函数调用App里面的回调函数,完成回调过程。
按照回调调用方式的实现不同,一般可分为同步回调与异步回调。我们一起分别来看看。
02、同步回调
代码1定义了回调接口,App需要实现该接口。
//【步骤1】定义回调接口
//该接口一般需要上层App进行实现
//底层则利用该接口类型完成对上层App的函数调用
public interface IMessage {
public void sendMessage(String msg, boolean isOK);
}
代码2为底层框架函数,在该函数中通过回调接口类型的引用,实现对App函数的调用。
//定义底层框架类
public class Android {
//框架类提供的库函数
public void sysSendMsg(String msg, IMessage iMsg){
int len = (msg == null)? 0 : msg.length();
//调用Android框架类中的其他函数
//完成发送消息的任务
//.....
//通过接口类型,完成对上层App的函数的调用
//【步骤4】调用回调函数
if(len <= 140){
iMsg.sendMessage(msg, true);
}else{
iMsg.sendMessage(msg, false);
}
}
}
代码3定义回调对象,也就是App类。
//【步骤2】定义回调对象
public class App implements IMessage {
//实现框架类提供的接口,返回框架执行的状态
//该函数为【回调函数】
@Override
public void sendMessage(String msg, boolean isOK) {
if(true == isOK){
System.out.println("Android had" + "been sended msg: " + msg + " is successfully!");
}else{
System.out.println("Android had " + "been sended msg: " + msg + " is failed!");
}
}
//App自定义的功能函数
//此外,由于向Android传入了App.this对象,
//其实也就是实现了【步骤3】回调函数的注册
public void appSendMessage(String msg, Android android){
//执行发送消息
android.sysSendMsg(msg, App.this);
//响铃一声
beer();
}
//执行一声响铃
public void beer(){
System.out.println("Beer....");
}
}
代码4为测试客户端,介绍了典型的回调使用方法。
public class TestCallback {
//测试客户端
public static void main(String[] args) {
//定义App对象引用
App app = new App();
//定义框架对象引用
Android android = new Android();
//App函数调用,并传入底层框架对象引用
app.appSendMessage("Hello world!", android);
}
}
03、异步回调
异步回调与同步回调的区别就在于是否需要等待底层框架模块的返回结果:异步回调不需要等待;同步回调需要一直等待完成。
异步回调实现的方式基本与同步回调方式类似,只是在上述App(上层类)实现方式(利用线程技术)有所差异,其他代码完全一致。
//App实现类
public class App implements IMessage {
//......
//App自定义的功能函数
//此外,由于向Android传入了App.this对象,
//其实也就是实现了回调函数的注册
//利用线程的方式,实现异步调用
public void appSendMessage(final String msg,
final Android android){
//利用线程的方式,实现执行发送消息的过程
new Thread(new Runnable(){
@Override
public void run() {
//执行发送消息
android.sysSendMsg(msg, App.this);
}
}).start();
//响铃一声
beer();
}
//......
}
04、通过内部类实现回调
此外,我们在传入App对象引用的时候,我们可利用【接口+匿名内部类】的技术组合达到相同的目的,具体实现方式见代码5。个人比较喜欢这样的实现方式,因为够简洁,够清楚。
//App自定义的功能函数
//此外,由于向Android传入了App.this对象,其实也就是实现了
//回调函数的注册
public void appSendMessageByAnonymous(final String msg,
final Android android){
//执行发送消息
//利用匿名内部类的形式传入App对象引用并实现回调函数
//这样的方式很简洁
android.sysSendMsg(msg, new IMessage(){
@Override
public void sendMessage(String msg, boolean isOK) {
if(true == isOK){
System.out.println("Android had been " +
"sended msg: " + msg + " is successfully!");
}else{
System.out.println("Android had been " +
"sended msg: " + msg + " is failed!");
}
}
});
//响铃一声
beer();
}