Java/Android中的函数调用&回调函数&自定义回调函数

少年击剑更吹箫,剑气箫心一例消。这篇文章主要讲述Java/Android中的函数调用& 回调函数& 自定义回调函数相关的知识,希望能为你提供帮助。
  在做Android自定义控件时遇到要自定义回调函数的问题,想想自己还暂时没有那么精深的技术,赶紧返过头回来再重新研究Java中回调函数的问题。然而不幸的是,网上太多杂乱的帖子和博客都是转来转去,而且都是那一篇“C中的回调函数.....指针.....java....”,一点看不出来是自己的思路,估计都是哪哪哪抄来的!(呵呵,要么就是吐槽对了,要么就是我水平太烂读不懂还妄加评论

Java/Android中的函数调用&回调函数&自定义回调函数

文章图片
)还有一些很不错的文章,我会在最后参考中加上链接,大家可以看看。
        那么来开始我们的正题——什么是回调函数?
        我们一步步深入,先从函数调用开始:
        什么是函数(方法)调用?        (别的什么语言的都忘了……呵呵,只看Java)Java中的函数调用无非就是(1)一个类中方法为了完成一个业务在执行过程中调用另一个方法,另一个方法也可以是自己,那就是递归啦;(2)不同类之间的函数调用,比如Class B(调用者Caller)中要调用Class A对象的一个方法(被调用者Callee)(不管A是作为B的成员,还是作为函数参数传进来)。方法调用是我们编程中必不可少的,可能我们平时视而不见罢了,否则一个工程的不同CLASS怎么协同工作呢?虽然简单,还是画个图说一下吧,待会对比一下可以更好的解释回调的机制:
         
Java/Android中的函数调用&回调函数&自定义回调函数

文章图片

          如上图Class B的函数method_B在执行过程中要调用成员a(Class A)的method_A1方法。
        我们刚开始学的时候都是这样做的。但是这样做存在问题,让我们来回顾一下我们当年学习的经过,不断将这个问题解释清楚:举个例子吧,不然嘴笨表达不清楚——A类是鸟类,B就是我们的工具类,现在我们要在工具类中完成这样的需求:通过工具类中的方法method_B完成不同鸟类飞的正确动作。
          第一阶段:显然就两个类完成不了这个需求!接着我们学习了继承,我们创建了“麻雀”、“大雁”、“鸵鸟”……各种“鸟”类子类,通过不同子类来完成不同的飞法,然后在工具类中创建不同子类的对象赋值给a,这样需求完成了。但是回头看看,我们创建了一大堆的子类,而且还用了隐式类型转换(子类赋值给父类),显然不够满意;
          第二阶段:后来,我们又学习了重载函数,在鸟类中创建一系列同名同名的“飞”函数,传入参数类型分别为麻雀、大雁……,这样我们就不用隐式转换了,直接调用鸟类对象a的飞方法,传入不同的大雁、麻雀……,a就能正确的飞了。这样需求也完成了,虽然避免了使用隐式转换,但是那些为数众多的子类可一个也没有落下。这样做显然也不符合我们的期望(我们的期望是什么?就是干最少的活,鸟就能正确的飞)。
          以上实现方式的问题就显而易见了:一方面我们要维护那些众多的子类,增加很大的工作量;另一方面,这样的编码缺乏灵活性,有多少种鸟你知道吗,每种鸟又是怎么飞的你知道吗,如果几种鸟极为相似,你是创建不同的类呢还是归为一类?所以有了下边这种实现方式,就是采用“回调函数”——
        什么是回调函数?【Java/Android中的函数调用& 回调函数& 自定义回调函数】        直接上图吧:
         
Java/Android中的函数调用&回调函数&自定义回调函数

文章图片

          如上图,回调函数中必然用到接口。下边是感觉写得好的一段理解:
在android的学习过程中经常会听到或者见到“回调”这个词,那么什么是回调呢?所谓的回调函数就是:在A类中定义了一个方法,这个方法中用到了一个接口和该接口中的抽象方法,但是抽象方法没有具体的实现,需要B类去实现,B类实现该方法后,它本身不会去调用该方法,而是传递给A类,供A类去调用,这种机制就称为回调。
        我认为,上图中B类的方法method_B在调用a对象的method_A1时,method_A1执行到interface的抽象方法不知道怎么实现,正好B在调用他的时候提供了具体实现,所以method_A1返回来调用method_B提供的实现,这就是回调。其实,回调函数就是在一个不确定实现的方法METHOD中用interface或者它的抽象方法留个口子,留给具体调用者(调用前边那个不确定的方法METHOD)在调用时提供具体实现来补上那个口子。从而达到更灵活地编码的目的,也大大减少了子类的使用。就拿上边没完的例子继续吧——
        我们这样来实现:先定义一个接口,接口中声明抽象方法“飞”;在“鸟”类的“起飞”方法中把接口对象作为一个参数传进来,剩下的该怎么做就怎么做,遇到要飞的地方不知道具体怎么飞就调用接口提供的抽象方法“飞”;在工具类中调用“鸟”类的“起飞”方法时要实现了抽象方法的对象作为参数传入,然后你想让它怎么飞就怎么飞,具体实现是你调用的时候现写的。怎么样,这样的实现好吧?不用隐式转换,不用大量子类,调用的时候遇到什么鸟就怎么飞,达到了我们少干活的目的!
        什么是自定义回调函数?        自定义回调函数,顾名思义,就是我们自己定义的回调函数。其实上边那个例子就是自定义回调函数!我们习惯上把别人定义好的回调函数叫作回调函数,Android系统中TextView、ImageView等和它们的子类控件的Onclick事件响应就是典型的回调机制。关于这个这位大虾讲得比我好——详细介绍Android中回调函数机制,详细看看会很有帮助的!
 
        一个简单的自定义回调函数的例子        最后在举个简单的有代码的例子,看一下回调函数的运行过程:
        首先,我们定义一个interface:
 
[java]  view plain  copy  
  1. public  interface  MyInterface  {   
  2.         void  sayYourName();    
  3. }   

          接着,我们定义一个类,其中一个方法以接口MyInterface类型的对象作为参数:
 
 
[java]  view plain  copy  
  1. public  class  MyClass  {   
  2.    
  3.         public  MyClass()  {   
  4.                 Log.e("WangJ",  "MyClass-constructor");                   //标注构造函数   
  5.         }   
  6.    
  7.         /*  用接口类型的对象作为输入参数  */   
  8.         public  void  sayYourName(MyInterface  myInterface){   
  9.                 Log.e("WangJ",  "MyClass-sayYourName_start");         //标注方法开始   
  10.                 myInterface.sayYourName();                                             //遇到不知道具体实现的时候就用接口的抽象方法   
  11.                 Log.e("WangJ",  "MyClass-sayYourName_finish");       //方法结束   
  12.         }   
  13. }   

          最后,我们在Activity中调用这个类,创建对象并调用其方法,期间实现接口中抽象方法的具体实现逻辑,供回调使用:
 
 
[java]  view plain  copy  
  1. public  class  MainActivity  extends  Activity  {   
  2.    
  3.         @Override   
  4.         protected  void  onCreate(Bundle  savedInstanceState)  {   
  5.                 super.onCreate(savedInstanceState);    
  6.                 setContentView(R.layout.activity_main);    
  7.    
  8.                 MyClass  myClass  =  new  MyClass();    
  9.                 myClass.sayYourName(new  MyInterface()  {                                          //实现接口并作为参数传入   
  10.                         @Override   
  11.                         public  void  sayYourName()  {   
  12.                                 Log.e("WangJ",  "callBack-interface-implementor");         //具体操作实现   
  13.                         }   
  14.                 });    
  15.         }   
  16. }   

          好了,运行一下(我们这个例子没有任何界面,即默认Activity的界面,看日志):
 
         
Java/Android中的函数调用&回调函数&自定义回调函数

文章图片

          运行的顺序就是我们之前理解的:在B中调用A中的方法,A中方法在运行到接口中抽象方法时返回B中寻找具体实现(这就是回调),回调完成后继续执行下边未完成的步骤。
 
        好了,以上就是我所认识的回调函数,听起来高深,在你弄懂以后发现也没有太大的难度。但是想想Java研发者在设计这种机制的时候是多么有远见啊(好崇拜,虽然不知道他是谁)!文笔有限,理解不够,如有不足或错误,欢迎指正!最后如约附上那几篇不错的文章——




    推荐阅读