JAVA回调函数

一. 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代码中无处不在。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值