回调机制是一种常见的设计模式,它把工作流内的某个功能按照约定的接口暴露给外部使用者,为外部使用者提供数据,或要求外部使用者提供数据。

之前对于回调一直是一知半解,而且总是停留在C++的函数指针的理解之中。但是回调在Android以及Javaweb框架中应用的比较多,为了更好的看代码,还是好好理解一下回调的原理,总结整理如下。

方法调用分类

从调用方式上看,调用方式可以分为三类:

  1. 同步调用:同步调用是一种阻塞式调用,也是我们在写程序中经常使用的;
  2. 回调:回调是一种双向的调用模式,也就是说,被调用的接口被调用时也会调用对方的接口;
  3. 异步调用:异步调用是一种类似消息或事件的机制,解决了同步阻塞的问题,回调是异步的基础。

在C++开发中通常是把一个方法的指针传递给事件源,当某一事件发生时通过函数指针调用这个方法(也称为“回调”)。Java并不支持方法指针,但是Java支持interface,可以通过interface可以实现相同的回调。通过定义一个简单的interface,声明一个被希望回调的方法。

Java中回调机制原理及示例代码

JAVA中的最基本的回调机制:CALLBACK通过接口来实现

例:
1.class A,class B
2.class A实现接口operate
3.class B拥有一个参数为operate接口类型的函数test(operate o)
4.class A运行时调用class B中test函数,以自身传入参数
5.class B已取得A,就可以随时回调A所实现的operate接口中的方法

其中第4和第5步是理解回调的关键,可以把第四步看做是”you call me “第五步看做是”i will call you back”,从这两个步骤中就可做很直观的理解为什么这种调用机制叫做回调了。

根据上述的回调过程,可以自定义一些回调接口和方法如下:

    // 实现回调的接口    public interface operate {        void doSth();    }    // 第二步,类A实现该接口并重载    public class A implements operate {        public B b;        public A() {            b = new B();        }        public void execute(){ // 第四步,相当于you call me            b.test(this);        }        @Override        public void doSth() {            System.out.println("doSth() in class A ");        }    }    // 第三步,类B含有一个类A为参数的函数test    public class B {        public B() {        }        public void test(operate o) {            o.doSth(); // 第五步,相当于i will call you back        }    }    public class TestCallback {        @Test        public void testCallBack() {            A a = new A();            a.execute();        }    }

Android中回调机制的应用-以View的点击事件为例

安卓中回调机制示例,以点击事件为例:
比如MainActivity相当于类A,Button相当于此处的类B,OnClickListener接口相当于此处的接口operater。不过Veiw的点击事件比示例中代码实现要复杂一些,但是流程是一样的。

先看类A,即此处的MainActivity:

    /** * MainActivity相当于类A,实现接口OnClickListener,并重载该接口中的onClick()方法 * 相当于前面的第二步 */    public class MainActivity extends Activity implements OnClickListener{        Button btn_cbd; // Button类相当于类B,存在于类A MainActivity中        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            setContentView(R.layout.activity_main);            btn_cbd = (Button) findViewById(R.id.bt_cbd);            // 在类A MainActivity中调用类B Button的方法setOnClickListener()并把自己作为参数传递过去            btn_cbd.setOnClickListener(this); // 第四步,相当于you call me        }        @Override        public void onClick(View v) {            Toast.makeText(getApplicationContext(), "onClick()", 1).show();        }    }

Button 是View的子类,所以直接看View的源码实现。主要复制了常用的setOnClickListener()方法和与该方法相关的performClick()方法。setOnClickListener()方法就是第三步中的以类A为参数的方法。

    public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {        /** * Register a callback to be invoked when this view is clicked. If this view is not * clickable, it becomes clickable. * * @param l The callback that will run * * @see #setClickable(boolean) */            public void setOnClickListener(@Nullable OnClickListener l) {                if (!isClickable()) {                    setClickable(true);                }                getListenerInfo().mOnClickListener = l;            }        /** * Call this view's OnClickListener, if it is defined. Performs all normal * actions associated with clicking: reporting accessibility event, playing * a sound, etc. * * @return True there was an assigned OnClickListener that was called, false * otherwise is returned. */            public boolean performClick() {                final boolean result;                final ListenerInfo li = mListenerInfo;                if (li != null && li.mOnClickListener != null) {                    playSoundEffect(SoundEffectConstants.CLICK);                    // 相当于第5步的i will call you back                    li.mOnClickListener.onClick(this);                    result = true;                } else {                    result = false;                }                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);                return result;            }    }

结合前面的简单的类A和类B的流程去看View点击事件的回调机制,相对而言就好理解很多了。要弄清楚回调机制首先要弄清回调函数的适用场景。一般为了使我们写的函数接近更加实用,就把一部分功能接口暴露出去,根据使用者自行定制,至于使用者是如何实现就不需要关心,唯一要做的就是定义好相关接口,这一设计允许了底层代码调用高层定义的子程序,增强程序灵活性。

更多相关文章

  1. Android中使用WebView与JS交互全解析
  2. 第二行代码学习笔记——第二章(2)
  3. Android重温--触屏事件
  4. android显示RGB565数据图像
  5. 【Android】利用安卓的数据接口、多媒体处理编写内存卡Mp3播放器
  6. Android(安卓)ProgressBar详解以及自定义
  7. 实现Android监控任意控件或按键双击事件方法
  8. Android工程中R类访问不到工程中的资源文件的解决方法
  9. Android(安卓)不得不说的VideoView的一些坑及其解决方案

随机推荐

  1. Android(安卓)Binder IPC详解-Android学
  2. Android的消息机制之ThreadLocal的工作原
  3. Android(安卓)sax解析XML数据
  4. Android(安卓)Bitmap图片处理,防止内存溢
  5. Android(安卓)socket 编程 实现消息推送(
  6. Android拾萃- Android(安卓)进程层次
  7. Android实现可拖动的悬浮按钮控件
  8. 【Android】学习笔记(5)——浅谈Handler
  9. [Android]Thread线程入门4--多线程
  10. Android(安卓)的 intent (手抄)