用了这么久的组件监听类,看了无数博文,终于真正理解回调机制

大家好,我是新人,很新的人,因为这是我的第一篇博客。我深知写博客的意义所在,并且我也很喜欢帮助别人,如果我的博客帮助到了你,我会很高兴、快

乐。当然,我还是个新手学生,如果有问题希望大家多多包涵,帮我指出来,感激不尽,毕竟大家都是在抱着一种助人为乐的心态在博客这个领域遨游,帮助别人快

乐自己。

这么久以来,一直被回调函数、回调机制困扰,一直不明白其中缘由,这几天决定狠下心一定要弄明白研究清楚,在看了无数个博客、帖子之后,自己总结了一

下。我学Android半年多了,目前还是个学生,我会用组件的监听,知道重写onclick方法,设置监听什么的。但是一直不知道它的原理是什么,在学习函数回调的时

候才明白其中缘由。

找个好的出发点和切入点,就先从组件的监听机制说起吧。

我们设置监听的顺序一般为:继承或者实现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 style="white-space:pre"></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方法。


如果你看到这里有一些思路了,那麻烦你,再重头浏览一遍,学会回顾,往往在回顾的时候才最有可能让人恍然大悟。


在学习回调的时候,我们应该理清思路。

首先要看定义,然后明白其意义,到底有什么用,然后结合例子,对照着分析,最后根据自己的经验努力去理解。

(比如肯定每个人都会对组件加监听,试着跟着它,顺藤瓜娃,说不定你离恍然大悟就不远了,到时候一声惊呼,“原来是这样”,我也恭喜你替你感到高兴了)


好了,谢谢大家,希望大家多多提建议或者意见,洗耳恭听哈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值