首页 > 编程知识 正文

java接口回调定义,接口回调代码

时间:2023-05-03 18:20:29 阅读:268488 作者:2300

一、回调的含义和用途 1. 什么是回调

一般来说,模块之间都存在一定的调用关系,从调用方式上来看,可分为三类:

同步调用:同步调用是一种阻塞式调用,即在函数A的函数体里通过书写函数B的函数名来调用之,使内存中对应函数B的代码得以执行。异步调用:异步调用是一种类似消息或事件的机制解决了同步阻塞的问题,例如A通知B后,他们各走各的路,互不影响,不用像同步调用那样,A通知B后,非得等到B走完后,A才继续走。回调:回调是一种双向的调用模式,也就是说,被调用的接口被调用时也会调用对方的接口,例如A要调用B,B在执行完又要调用A。

2. 回调的用途

回调一般用于层间协作,上层将本层函数安装在下层,这个函数就是回调,而下层在一定条件下触发回调。例如作为一个驱动,是一个底层,他在收到一个数据时,除了完成本层的处理工作外,还将进行回调,将这个数据交给上层应用层来做进一步处理,这在分层的数据通信中很普遍。

二、为什么会存在回调机制 举例1:

有一位老板(上层模块)很忙,他没有时间盯着员工(下层模块)干活,然后他告诉自己的雇员,干完当前这些事情后,告诉他干活的结果。这个例子其实是一个回调+异步的例子,再举一个例子,A程序员写了一段程序a,其中预留了回调函数接口,并封装好了该程序,程序员B让a调用自己的程序b中的一个方法,于是,他通过a中的接口回调自己b中的方法。下面把上面的例子变成代码

1.首先创建一个回调接口,让老板得告知干完活如何找到他的方式:留下老板办公室地址:

/** * 此接口为联系的方式,不论是电话号码还是联系地址,作为 * 老板都必须要实现此接口 */ public interface CallBackInterface { public void execute(); }

2.创建回调对象,就是老板本人,因为员工干完活后要给他打电话,因此老板必须实现回调接口,不然员工去哪里找老板?

/** * 老板是作为上层应用身份出现的,下层应用(员工)是不知道 * 有哪些方法,因此他想被下层应用(员工)调用必须实现此接口 */ public class Boss implements CallBackInterface { @Override public void execute() { System.out.println("收到了!!" + System.currentTimeMillis()); } }

3.创建控制类,也就是员工对象,他必须持有老板的地址(回调接口),即使老板换了一茬又一茬,办公室不变,总能找到对应的老板。

/** * 员工类,必须要记住,这是一个底层类,底层是不了解上层服务的 */ public class Employee { private CallBackInterface callBack = null; //告诉老板的联系方式,也就是注册 public void setCallBack(CallBackInterface callBack){ this.callBack = callBack; } //工人干活 public void doSome(){ //1.开始干活了 for(int i=0;i<10;i++){ System.out.println("第【" + i + "】事情干完了!"); } //2.告诉老板干完了 callBack.execute(); } }

4.测试类代码:

public class Client { public static void main(String[] args) { Employee emp = new Employee(); //将回调对象(上层对象)传入,注册 emp.setCallBack(new Boss()); //开启控制器对象运行 emp.doSome(); } } 举例2:

对于回调函数的理解可以参照C或C++中对回调函数的定义:

程序在调用一个函数时,将自己的函数的地址作为参数传递给程序调用的函数时(那么这个自己的函数称回调函数)

然而Java中没有指针,不能传递方法的地址,一般采用接口回调实现:把实现某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。

例如:

一读者想借《软件技术学习与实践》这本书,但这本书已被其他读者借走了。于是,读者与图书馆管理员间发生了以下对话:

读者:“我把我的电话号码告诉你,等书一到就马上通知我。”

管理员:“好的。另一读者把书还回来后,马上给您打电话,书我先帮您留着。”

在上述这个场景中,读者就是“回调对象”,管理员就是“控制器对象”,读者的电话号码就是“回调对象的方法”。

在控制器类中引用了回调对象,因此就能调用回调方法,当控制器进行某些判断之后(如:监听鼠标单击操作)就会自动调用回调方法!简易流程图如下:

举例3: 假如有两个类 classAclassB

如果A要调用B的方法,则:在classA中创建B的对象
如果B要调用A的方法,则:在classB中创建A的对象

两个类构成一个循环的关系,“你中有我,我中有你”。这样操作在实际中最不可取,因为耦合度最高。所以要想办法打断其中的一条线,打破循环关系。
怎么打断呢?——接口回调

接口回调三部曲:

一、 在B类中创建事件接口interface

//B类是自定义Video类。在B类中创建,供逻辑层来实现具体逻辑public interface ADVideoPlayerListener { public void onBufferUpdate(int time); public void onClickFullScreenBtn(); public void onClickVideo(); public void onClickBackBtn(); public void onClickPlay(); public void onAdVideoLoadSuccess(); public void onAdVideoLoadFailed(); public void onAdVideoLoadComplete(); }

二、在A类中implement此接口

在逻辑层中实现此接口,并且实现相应方法

public class VideoAdSlot implements CustomVideo.ADVideoPlayerListener{}

三、在A类中创建B类实例时,同时为B类setListener

在创建B类(自定义类CustomVideo)的时候,同时为它绑定一个Listener。

private void initVideoView() { //创建B类(自定义Video类) mVideoView = new CustomVideoView(mContext, mParentView); if (mXAdInstance != null) { mVideoView.setDataSource(mXAdInstance.resource); //注入一个listener mVideoView.setListener(this); } mParentView.addView(mVideoView); }

这样当,在B类(CustomVideo)中触发对应事件时,就会通知到A类(逻辑层)实现此方法。

private ADVideoPlayerListener listener;@Override public void onClick(View v) { if (v == this.mMiniPlayBtn) { if (this.playerState == STATE_PAUSING) { if (Utils.getVisiblePercent(mParentContainer) > SDKConstant.VIDEO_SCREEN_PERCENT) { resume(); this.listener.onClickPlay(); } } else { load(); } } else if (v == this.mFullBtn) { this.listener.onClickFullScreenBtn(); } else if (v == mVideoView) { /** *当点击视频区的时候,就会调用listener的onClickVideo *当事件真正产生的时候,就会调用A类(逻辑层)的onClickVideo() *这样也就完成了相互的通信。 *A类既可以调用B类的的方法,B类也可以调用A类中的方法。 */ this.listener.onClickVideo(); } } 总结:

在三层中,当业务层调用数据层时,是不需要把业务层自身传递到数据层的,并且这是一种上层调用下层的关系,比如我们在用框架的时候,一般直接调用框架提供的API就可以了,但回调不同,当框架不能满足需求,我们想让框架来调用自己的类方法,怎么做呢?总不至于去修改框架吧。许多优秀的框架提几乎都供了相关的接口,我们只需要实现相关接口,即可完成了注册,然后在合适的时候让框架来调用我们自己的类。

最后,再举一例,为了使我们写的函数接近完美,就把一部分功能外包给别人,让别人个性化定制,至于别人怎么实现不管,我唯一要做的就是定义好相关接口,这一设计允许了底层代码调用高层定义的子程序,增强程序灵活性,和反射有着异曲同工之妙,这才是回调的真正原因!

用一段话来总结下回调:上层模块封装时,很难预料下层模块会如何实现,因此,上层模块只需定义好自己需要但不能预料的接口(也就是回调接口),当下层模块调用上层模块时,根据当前需要的实现回调接口,并通过注册或参数方式传入上层模块即可,这样就实现下层调用上层,并且上层还能根据传入的引用来调用下层的具体实现,将程序的灵活性大大的增加了。

参考:

http://www.jcodecraeer.com/a/chengxusheji/java/2012/0822/370.html
https://blog.csdn.net/bjyfb/article/details/10462555

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。