我们设置监听的顺序一般为:继承或者实现Listener接口,然后重写onclick方法,这里就是自己想要实现的一些操作;有一个组件的引用,就说定义button吧;
button设置Listener监听。大概就是三步,我们就完成了组件的监听。如果把监听和回调结合起来的话,那应该还少了一步就是实现button的click方法,当然,这里是
Android系统在我们对组件进行操作的时候自动调用的,所以,这就是我们只需要设置监听就能相应事件的缘由了。
我们来看看代码吧。
<span style="font-size:14px;">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();
}
}</span><span style="font-size:12px;"> </span>
</pre><span style="font-size:12px;"></span><p><span style="font-size:12px;"><span ></span></span><pre name="code" class="html">
看看上面的代码,首先有一个接口,接口里面有一个回调函数,其次组件里面有一个click方法,还有设置监听的方法,最后main方法里面的调用方是有一个组件
的引用,组件设置了监听,然后重写了接口的onclick方法,实现自己想要的操作。button.click()就是刚才说的Android系统框架在组件被操作的时候 自动 调用的。
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回
调函数。回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
回调函数在监听中可以达到异步的效果,还有就是我可以让别人调用我指定的方法。
原理就在于,我主调用方,我实现了一个接口,这个接口有一个方法,这个方法就是回调方法,我在调用被调用方里面的方法的时候,我就可以重写回调方法, 让被 调用方
去执行我要它执行的语句。我是主动方,我要是想要你执行你立马就去执行,如果没有让你执行,你也就算是待命、监听的状态。被调用方是不需要实现方法的,它只是提供一个
方法,然后我是主调用方,我调用你,让你执行我要你执行的东西。
如果拿组件监听事件的例子来说就是,我是一个activity,主动调用方,我实现了一个监听的接口,然后组件类就是被调用方。我现在要重写onclick方法,组件类里 面也有一
个onclick方法,不过它是执行我重写的方法语句。一般情况下,组件类里面都含有一个listener,然后有setListener方法,还有一个click方法,里面执行listener的onclick回调方法。
我是主调用方,我一般会new一个listener接口,然后重写listener接口的onclick方法,然后让被调用方组件类setListener。
正常情况下是该再调用一下组件类的click方法,但是这里是监听,也就是说,只有在组件被点击的时候,Android系统框架会自动调用组件类的click方法,实现达到回调的目的。
仔细看看,如果再对照下面回调的定义来看,你就会发现的的确确有些苗头了。
那我们就看看回调的定义吧。有很多个版本,我做一个总结。
百度百科:
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
WINDOWS:
在WINDOWS中,程序员想让系统DLL调用自己编写的一个方法,于是利用DLL当中回调函数(CALLBACK)的接口来编写程序,使它调用,这个就 称为回调。在调用接口时,需要严格的按照定义的参数和方法调用,并且需要处理函数的异步,否则会导致程序的崩溃。
CSDN xiananming:
就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法。
我是看了xiananming的这篇博客好几遍了,链接在这里大家可以看看点击打开链接
客户与服务:
当然这里是比较复杂的,看了比较头晕的,那我们结合实例来说说。网上有很多个版本。
客户程序C调用服务程序S中的某个函数A,然后S又在某个时候反过来调用C中的某个函数B,对于C来说,这个B便叫做回调函数。例如Win32下的窗口过程函数就是
一个典型的回调函数。一般说来,C不会自己调用B,C提供B的目的就是让S来调用它,而且是C不得不提供。由于S并不知道C提供的B姓甚名谁,所以S会约定B的
接口规范(函数原型),然后由C提前通过S的一个函数R告诉S自己将要使用B函数,这个过程称为回调函数的注册,R称为注册函数。Web Service以及Java的RMI
都用到回调机制,可以访问远程服务器程序。
打电话:
有一天小王遇到一个很难的问题,问题是“1 + 1 = ?”,就打电话问小李,小李一下子也不知道,就跟小王说,等我办完手上的事情,就去想想答案,小王也不会傻傻的拿着电话去等小李的答案吧,于是小王就对小李说,我还要去逛街,你知道了答案就打我电话告诉我,于是挂了电话,自己办自己的事情,过了一个小时,小李打了小王的电话,告诉他答案是2
妈妈叫吃饭:
你饿了,想吃饭,就一会去问你妈一声"开饭没有啊?"
这就是正常函数调用.
但是今天你妈包饺子,花的时间比较长,你跑啊跑啊,就烦了.于是你给你妈说,我先出去玩会,开饭的时候打我手机.
等过了一阵,你妈给你打电话说"开饭啦,回来吃饭吧!"
其中,你告诉你妈打手机找你,就是你把回调函数句柄保存到你妈的动作.你妈打电话叫你,就是个回调过程.
这些例子如果你没有理解到的话,那是再正常不过了,因为跟我一样,我不知道回调的意义是什么,所以不好理解。
我觉得说这么多,最有必要的就是说说回调的意义何在了。
因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。简而言之,回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。
按我自己的话来说就是,回调能提高代码的复用性,能够提供一种我叫你答而且答的是我想听的内容的机制,能够实现异步操作,能够提供监听机制,能够层与层之间剥离开来(也就是,降低代码的之间的耦合度,关联性,使代码独立出来,复用性更高了),能够使代码执行地更规范(一个提供规范,一个按规范执行)
下面看一个例子,来加深理解:
<span style="font-size:14px;">public class TestObject {
/**
* 一个用来被测试的方法,进行了一个比较耗时的循环
*/
public static void testMethod(){
for ( int i= 0 ; i< 100000000 ; i++){
</span><pre name="code" class="java"><span style="font-size:14px;">public class Tools {
/**
* 测试函数使用时间,通过定义CallBack接口的execute方法
* @param callBack
*/
public void testTime(CallBack callBack) {
long begin = System.currentTimeMillis(); //测试起始时间
callBack.execute(); ///进行回调操作
long end = System.currentTimeMillis(); //测试结束时间
System.out.println("[use time]:" + (end - begin)); //打印使用时间
}
public static void main(String[] args) {
Tools tool = new Tools();
tool.testTime(new CallBack(){
//定义execute方法
public void execute(){
//这里可以加放一个或多个要测试运行时间的方法
TestObject.testMethod();
}
});
}
} </span>
这种方法的不足之处就在于,测试方法写在了testTime里面,如果一旦指定了就没办法修改了,而且testTime这个方法也就不可复用了。
所以来看看加上回调之后的好处。
<span style="font-size:14px;">public class Tools {
/**
* 测试函数使用时间,通过定义CallBack接口的execute方法
* @param callBack
*/
public void testTime(CallBack callBack) {
long begin = System.currentTimeMillis(); //测试起始时间
callBack.execute(); ///进行回调操作
long end = System.currentTimeMillis(); //测试结束时间
System.out.println("[use time]:" + (end - begin)); //打印使用时间
}
public static void main(String[] args) {
Tools tool = new Tools();
tool.testTime(new CallBack(){
//定义execute方法
public void execute(){
//这里可以加放一个或多个要测试运行时间的方法
TestObject.testMethod();
}
});
}
} </span><span style="font-size:12px;"> </span>
大家看看这里,这样一变,testTime就只是提供一个规定约束行为的方法,并没有真正的实现,真正的实现在main方法里面重写的execute方法。你们看,是不
是callbak这个接口就把main方法(我称为调用方)和testTime(被调用方)联系起来了。好处就是,testTime不管实现了,要实现你调用的我时候实现,所以
testTime可以给不同的调用者用,达到了复用的效果。
如果结合xiananming的A类和B类的定义来说,就是这里的main方法是A,testTime是B,A实现了callback接口,并且有一个B的引用,调用B的testTime方法,并
且以参数的形式把callback传递给了B,B反过来调用了A重写的execute方法,这就是回调了,你(A)喊我(B),你调我的testTime方法,你让我执行操作,
然后,我又反过来调用你的execute重载方法,这就是回调。
如果再结合监听来说,就是activity中有button引用,button设置了接口Listener监听,activity执行了button里面的click方法,button又反过来回调activity中重写监 听Listener接口的onclick方法。
如果你看到这里有一些思路了,那麻烦你,再重头浏览一遍,学会回顾,往往在回顾的时候才最有可能让人恍然大悟。
在学习回调的时候,我们应该理清思路。
首先要看定义,然后明白其意义,到底有什么用,然后结合例子,对照着分析,最后根据自己的经验努力去理解。
(比如肯定每个人都会对组件加监听,试着跟着它,顺藤瓜娃,说不定你离恍然大悟就不远了,到时候一声惊呼,“原来是这样”,我也恭喜你替你感到高兴了)