一. java回调机制:
所谓回调,就是客户程序C调用服务程序S中的某个函数A,然后S又在某个时候反过来调用C中的某个函数B,对于C来说,这个B便叫做回调函数。
软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。
同步调用:一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;
回 调:一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;
异步调用:一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。
回调和异步调用的关系非常紧密:使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。
二 .正常情况下开发人员使用已经定义好的API,这个过程叫Call。但是有时这样不能满足需求,就需要程序员注册自己的程序,然后让事先定义好多API在合适的时候调用注册的方法,这叫CallBack。
“当通常大家说的回调函数一般就是按照别人的定好的接口规范写的,等待别人调用的函数,在C语言中,回调函数通常通过函数指针来传递;在Java中,通常就是编写另外一个类或类库的人规定一个接口,然后你来实现这个接口,然后把这个实现类的一个对象作为参数传给别人的程序,别人的程序必要时就会通过那个接口来调用你编写的函数。”
使用技巧:定一个接口,在接口中声明我们想调用的方法。在另一个方法中注册刚定义的回调接口//定义接口
public interface Callback {public void executeMethod();
}
public class Tools {public void getTime(Callback call) {
long start = System.currentTimeMillis();
call.executeMethod();
long end = System.currentTimeMillis();
System.out.println("cost time=" + (end - start));
}
}
public class Main {
public static void main(String[] args) {
Tools tool = new Tools();
tool.getTime(new Callback() {
public void executeMethod() {
new Main().testMethod();
}
});
}
public void testMethod() {
for (int i = 0; i < 10000; i++) {
System.out.print("");
}
}
}
------------------------------
MainSlideTabActivity类中:
private static IDataChange dataInstance = null;
public static void setOnDataChangeListener(IDataChange dataInstance){
MainSlideTabActivity.dataInstance = dataInstance;
}
if(dataInstance != null){
dataInstance._dataChange();
}
interface IDataChange {
public void _dataChange();
}
HomePageActivity类中:
IDataChange dataInstance = new IDataChange(){
@Override
public void _dataChange() {
refreshData();
}
};
MainSlideTabActivity.setOnDataChangeListener(dataInstance);
抽象:我们在定义一个抽象类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模版),这种研究问题的方法称为抽象。你可以这样来想,抽象就是一个类的最基础的东西,比方说人,他的抽象类可能就是都从母体出来,有皮肤。但具体到你是黑人,白人,还得黑人类,白人类来说明 。
封装:就是将类的属性包装起来,不让外界轻易的知道他的内部实现。只提供给你对外的接口让你来调用。好处可以增强模块的独立性。如设置属性或方法的访问权限(private、protected、public、默认)。
继承:就是从父类把它的有用的东西拿过来自己用,不用在自己去实现了,像母亲会把双眼皮传给女儿,不用她自己去割了 。
多态:一个对象变量可以指向多种实际类型的现象。一个人,在不同场合下,有不同的身份,不同的状态。比如在家里,你是父母的孩子;在学校,你就是学生;在公司,你就是老板的职员。再比如在接口总定义一个run()方法,是什么在跑,汽车还是马?通过不同类的实现来表示相似的逻辑。
顺便说一下重载和重写(覆盖)的区别:
重载:相同的方法名,不同的实现机制(通过传入不同个数或类型的参数)。当程序运行过程中自己去判断到底该调用谁。比方说打人,那么多人,当你打起群架来,该打谁就打谁,事前你也不知道。
重写:从父类继承而来的方法不能满足需要的情况下,可以将此方法的逻辑在子类中重新实现。我们最常用的就是重写toString()方法了
Android回调机制
一、回调函数
回调函数就是一个通过函数 的指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
详细解释:
客户程序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都用到回调机制,可以访问远程服务器程序。
下面举个通俗的例子:
某天,我打电话向你请教问题,当然是个难题,^_^,你一时想不出解决方法,我又不能拿着电话在那里傻等,于是我们约定:等你想出办法后打手机通知我,这样,我就挂掉电话办其它事情去了。过了XX分钟,我的手机响了,你兴高采烈的说问题已经搞定,应该如此这般处理。故事到此结束。这个例子说明了“异步+回调”的编程模式。其中,你后来打手机告诉我结果便是一个“回调”过程;我的手机号码必须在以前告诉你,这便是注册回调函数;我的手机号码应该有效并且手机能够接收到你的呼叫,这是回调函数必须符合接口规范。
JAVA中不允许直接操作指针,那它的回调是如何实现的呢?
答案:它是通过接口或者内部类来实现的。
JAVA方法回调是功能定义和功能实现分享的一种手段,是一种耦合设计思想。作为一种架构,必须有自己的运行环境,并且提供用户的实现接口。
1. 定义接口 Callback ,包含回调方法 callback()
2. 在一个类Caller 中声明一个Callback接口对象 mCallback
3. 在程序中赋予 Caller对象的接口成员(mCallback) 一个内部类对象如
new Callback(){
callback(){
//函数的具体实现
}
}
这样,在需要的时候,可用Caller对象的mCallback接口成员 调用callback()方法,完成回调。
二、回调机制在Android框架中的使用
1、在Activity中定义了很多生命周期的不同状态要调用的方法,这些方法都是空实现,系统框架要调用,用户也要调用来实现。
实例(对于Android界面上Button点击事件监听的模拟):
a.定义接口
public interface OnClickListener {
public void OnClick(Button b); }
b. 定义Button
public class Button {
OnClickListener listener;
public void click() {
listener.OnClick(this);
}
public void setOnClickListener(OnClickListener listener) {
this.listener = listener;
}
}
c. 将接口对象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();
}
}
机制原理如上,那数据传递依靠接口怎么传递呢?
/*
* @category 利用xUtils框架封装get方法,IOAuthCallBack是数据接口回调,send方法里面 有异步任务方法,
* 传统返回数据方法可能返回数据不正确。
*/
public class xUtilsGet {
public void getJson(String url,RequestParams params,final IOAuthCallBack iOAuthCallBack){
HttpUtils http = new HttpUtils();
http.configCurrentHttpCacheExpiry(1000 * 10);
http.send(HttpMethod.GET, url, params, new RequestCallBack() {
@Override
public void onFailure(HttpException arg0, String arg1) {
// TODO 这里的实现
}
@Override
public void onSuccess(ResponseInfo info) {
// TODO Auto-generated method stub
iOAuthCallBack.getIOAuthCallBack(info.result);
}
});
}}
我用的是xUtils开发框架然后返回数据的时候用的是接口回调,接口定义如下:
public interface IOAuthCallBack {
public void getIOAuthCallBack(String result);
}
上层函数定义如下:
public void getCataJson(int cityId,IOAuthCallBack iOAuthCallBack) {
String url = http://xxxxxxx;
RequestParams params = new RequestParams();
params.addQueryStringParameter(currentCityId, cityId+);
getJson(url,params,iOAuthCallBack);
}
getCataJson是在你想得到数据的类中调用,然后传入参数和接口对象,接口对象中是要对最终数据进行处理。具体机制原理如上。这样就可以避免接口回调中的多线程数据不一致问题。
-------------------------------------------------
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
init();
}
private void init() {
for (int i = 0; i < 10000; i++) {
if (i == 9527) {
showToast(i, new CallBackInterface() {
@Override
public void callBackFunction(int i) {
}
});
}
}
}
//定义函数,其中一个参数为CallBackInterface类型
private void showToast(int i, CallBackInterface callBackInterface) {
callBackInterface.callBackFunction(i);
}
//定义接口.且在接口中定义一个方法
public interface CallBackInterface {
public void callBackFunction(int i);
}
}
--------------------------------------------
首先,服务器端创建一个回调接口
//声明一个接口
public interface ICallBack {
void postExec();
}
//另外一个类有方法里面有个参数是这个接口类型的对象
public class FooBar {
private ICallBack callBack;
public void setCallBack(ICallBack callBack) {
this.callBack = callBack;
}
public void doSth() {
callBack.postExec();
}
}
//实现回调
public class Test {
public static void main(String[] args) {
FooBarfoo = new FooBar();
foo.setCallBack(new ICallBack() {
public void postExec() {
System.out.println("method executed.");
}
});
foo.doSth();//调用函数
}
}
程序的本质就是代码跳转,不管同步异步反射接口虚函数,本质上都是函数调用。函数我们要调用它,就需要它的指针,不同语言通过不同的方式来得到这个指针。而我们定义的接口其实就是一个函数指针,那么注册过程,其实就是相当于对那个函数指针赋值。通过这个函数指针来调用我们定义的自实现函数。利用函数指针实现回调,在RIL的C代码中无处不在。