强迫深究Java中的回调

前言:关于Java中的回调一直是困扰着我的一个问题,虽然感觉好像没什么好说的,但是作为强迫症患者,就会深究其中无法自拔。例如:为什么要回调?回调和委派是什么关系?感觉要实现委派,回调似乎是少不了的。那么Android中的事件处理委派机制和回调机制的区别究竟是什么?接下来就来研究一下Java中的回调吧。


一、什么是回调?

我打算还是用大家习惯的打电话的例子来解释回调。有一天,小明打电话给小王,问他下午要不要一起去打球?小王很想一起打,但是他下午可能会有其他的事情,基于这个考虑,小王不能立即给小明答案。于是他对小明说:“我下午看看有没有时间,再给你答复”。于是他们就挂了电话,小明就只要等待小王的电话就行了。这种情况就是生活中的回调例子。
客户端(小明)向服务端(小王)请求某种服务,然后客户端可以做其他事情,等到服务端将服务处理完之后,就通知客户端做完它要求的事情了,可以验收了,这个通知客户端的过程就叫做回调。

二、为什么要引入回调?

那么为什么要引入回调呢?其实答案已经隐藏在上面的例子中了。程序调用分为同步调用和异步调用,区别如下:
(所谓同步调用,就是A请求B的服务,然后A就一直等待,一直到B服务完成返回给A,A才能继续执行,这种方案实现比较简单,但是显然效率不高。
异步调用相对于同步调用,A发送一个请求消息之后,便可以做其他的事情,等到B完成服务之后再反过来通知A,这其实就是回调)
综上,我们可以知道,回调是为了解决异步调用的问题
那么Java和C++回调的区别是什么呢?
C++我们知道是允许指针的,于是C++中基于指针的回调就显得很自然了,这种回调可以提供客户端很大的灵活性,因为此时客户端操作的是服务端对象的实体。
Java是没有指针的,但是也逃不开回调这个课题,于是Java中采用了一种基于接口的回调(也就是我们常说的接口回调),这种回调是安全的,不像C++,Java可以通过接口限制客户端的调用权限。当然Java中的回调不止接口回调 这一种 ,这里以接口回调为例。

三、接口回调的实例和原理。

首先编写服务端程序(相当于上面例子中的“小王”),程序中已添加了必要的注解。

package test;

 

public class Service {


private Callback mCallback;

/**

 * 在服务端定义一个回调接口

 */

public interface Callback {

void callbackFunction();

}

 

/**

 * 客户端初始化时需要传入一个Callback接口的实现类。

 *

 * @param mCallback

 *            相当于客户端抛给服务端的“钩子”,服务端将通过这个“钩子”实现回调。

 */

public Service(Callback mCallback) {

this.mCallback = mCallback;

}

 

/**

 * 服务端提供给客户端的服务

 */

public void startThinking() {

for (int i = 0; i < 5; i++) {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("I'm thinking!!!:" + i);

}

System.out.println("Service done!");

// 回调客户端的回调函数,mCallback是客户端传过来的“钩子”

mCallback.callbackFunction();

}

}


接着是客户端的代码:

package test;

 

import test.Service.Callback;

 

public class Client {

 

public static void main(String args[]) {

Callback mCallback = new Callback() {

@Override

public void callbackFunction() {

System.out.println("Back to client!");

}

};

//这里相当于将接口的实现类传给了服务端,提供了服务端回调的一个“钩子”

Service mCallee = new Service(mCallback);

//请求服务端的服务,相当于例子中小明打电话问小王的过程,接下来就只要等小王打回来就行了(回调)

mCallee.startThinking();

}


执行结果:


小结:从上面可以看出,这种回调是基于接口的一种回调,客户端将接口的实现类(“钩子”)丢给服务端,服务端做完事情之后这个“钩子”使回调成为可能,通过“钩子”回调了客户端代码。

大致原理如图:


四、回调的实例,Android事件处理机制。

我们知道,Android中的事件处理有两种方案,一种是基于监听器的委派机制,一种是回调机制。前者是将事件响应的代码与组件本身分离,也是较为常见的方法。后者是通过重写自定义组件的回调方法实现事件响应的,组件和事件响应代码混在一起。
这里想讲的是很多人会因为这两个方案的命名而对回调的概念产生怀疑,事实上,我们可以查看源码,发现这种基于监听器的委派机制实际上也是用到了回调。例如:
button.setOnClickListener(new OnClickListener(){
@Override
... onClick(View v)
{
...;
}
});
我们可以观察到这种逻辑跟上面讨论的是一致的,将OnClickListener接口的实现类(“钩子”)传递给服务端,然后等待服务端的回调。所以不能被名字混淆,认为基于监听器的事件处理没有用到回调...由此可能会产生对其概念的深深怀疑...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值