作为新手,不得不说学习是个艰难的过程。这几天一直在看关于回调机制方面的问题,经过几天的摸索,开始对android中的回调机制有了一点理解,下面做一个记录,有的是从别处借鉴过来的,有的是自己的一点理解,如有错误或者遗漏之处,欢迎指正。 首先,什么是回调函数?android中怎么实现回调函数?为什么要使用回调函数?
简单的说,回调函数就是通过其指针来调用的函数(这句话确实够简单的,下面会详细的描述);回调函数不会被自己所在的对象调用,只会在调用别人的方法的时候反过来被调用。我们知道android程序是通过java来实现的,java中是没指针的,那么怎么实现回调呢,通过接口、或者抽象类。
实现步骤:
1、定义一个接口,其中包含一个方法a;
2、定义一个实现这个接口的类A,实现方法 a(此处的a就是传说中的回调函数,此处不一定要在声明类的时候实现这个接口,也可以在类中去实现这个接口,我会分别举例子)
3、定义一个类B,在B中定义一个方法b,b以第一步中定义的接口作为参数;
4、在A中调用方法b,把自己作为参数传递进去;
5、在B中通过传递进来的参数A(实现了接口)去调用a,这就实现了回调;
至于为什么要使用回调函数呢?在一位大神的博客里面看到这句话“回调功能是实现功能和定义分离的一种手段,是一种松耦合的设计思想”,有的人就会问了,为什么要实现定义和功能分离呢?我们在刚开始接触面向对象的这个概念的时候,应该经常听到这种说法:面向对象是要实现高内聚、低耦合,方便程序的修改和扩展。我觉得函数的定义和功能的分离应该也是这个道理吧。在下面的例子中我会在注释中从另外一个方面说明回调函数的必要性。
其次,看代码吧
代码1,在声明类的时候实现接口:
package com.callback;
/* 第一步:定义一个接口,其中包含一个方法a*/
public interface Callback {
public void a(int i);
}
package com.callback;
/* 第二步:定义一个实现这个接口的类A,实现方法 a*/
public class A implements Callback{
static B b = new B();
/* 此处为什么要定义一个常量呢?
* 我是想从另一个方面(松耦合的设计思想算是一方面吧)说明回调方法的必要性,
* 暂时先不用管,后面会继续说明的*/
final int Constant = 1;
@Override
/* 回调方法不会在A类中被调用的,注意看待会他会在哪被调用 */
public void a(int result) {
// TODO Auto-generated method stub
System.out.println(result);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
/* 第四步:在A中调用方法b,把自己作为参数传递进去,
* 此处A中的常量Constant,也会随着A被传到B中*/
b.b(new A());
}
}
package com.callback; /* B中要干什么事呢? * 前面说过,回调函数要实现方法的定义和功能分离 * 回调方法a是在A中定义的,其具体的功能会在B中来定义*/ public class B { A a = new A(); /* 此处的常量跟A中的常量一样,后面我会解释的*/ private final int Constant = 2; /* 第三步:定义一个类B,在B中定义一个方法b,b以第一步中定义的接口作为参数*/ public void b(A a) { // TODO Auto-generated method stub /* 此处也从另一个方面彰显了回调方法的作用. * 现在可以说说A、B中分别定义的两个常量的作用了 * A中的常量其实没什么好说的,重要的是B中的常量, * 回调的方法a要实现的功能是将两个常量相加,并输出, * 但是B中的常量有时候A是无法访问的, * 就像现在,我把B中的常量定义为private的。 * 打个比方,苹果公司要生产一批iphone,但是美国没有生产iphone的材料(假设的), * 只有生产iphone的技术,中国有生产iphone的材料, * 于是美国佬就拿着自己的技术来到中国,跟富士康的老大商量,让让富士康从中国获取材料, * 然后生产iphone,这里所说的美国就是A类,技术就是A中的常量了, * 中国就是B类,材料就是B类中的常量了,iphone就是result * 技术 + 材料 = 一部iphone*/ int sum = a.Constant + this.Constant; a.a(sum);//第五步:在B中通过传递进来的参数A(实现了接口)去调用方法a } }
代码2,在类中实现接口:
其实我接下来要说的这种情况应该是android中最常见的使用回调机制的地方了,只是我们没有注意到罢了,
为Button添加事件监听的时候
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
/***********/
}
});
其实就使用了回调机制,在上面的例子中,接口和B类是我们自己定义的,对应到这段代码中,其中的接口OnClickListener、类Button是系统定义好的,我们只需要拿过来用就行了
让我们来看看View的源码(很长的,只贴片段)
(为什么要看View的源码呢?因为Button是View的间接子类,View中的方法Button中都有)
/**
* Register a callback to be invoked when this view is clicked. If this view is not
* clickable, it becomes clickable.
*
* @param l The callback that will run
*
* @see #setClickable(boolean)
*/
public void setOnClickListener(OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
看到其中的setOnClickListener()方法了吧,说明一下,此处的Button中的setOnClickListener()方法就相当于代码1中,B类中的b方法了,把接口
OnClickListener作为参数,
这就是传说中的在类中实现接口了
再补充一点,在创建线程的时候,我们都知道一般有两种做法
public class ClassName extends Object implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
/********/
}
}
还有一种
Thread thread = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
/********/
}
});
大家可能已经发现了,这两中创建线程的方法,都使用了回调机制,刚好对应着上面我举出的两个例子,在类声明的时候实现接口和在类中实现接口。
还是不明白的话,可以再看看这位大哥的说明,相当精辟,在此也对这位大哥表示感谢
http://m.blog.csdn.net/blog/xiaanming/8703708