Android接口回调,最简单的理解方式

在做项目的过程中,做了很多回调,好像是一种自然而然的事。回过头来品味,还是十分有趣的。在Android中为什么定义那么多接口,很大一部分都是用来接口回调的,包括那些OnListener等系统给出接口都是这种用法。

1.Java中的回调函数

理解一个东西,必须从它的本源入手,再实例化到生活事例中,加深理解,毕竟程序是对现实生活的一种抽象。

而Android中的回调,遵循的基本思想是Java中的回调函数。

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

Java 中没有指针的概念,通过接口和内部类的方式实现回调的功能:
1. 定义接口 Callback ,包含回调方法 callback()
2. 在一个类Caller 中声明一个Callback接口对象 mCallback
3. 在程序中赋予 Caller对象的接口成员(mCallback) 一个内部类对象如
new Callback(){
callback(){
//函数的具体实现
}
这样,在需要的时候,可用Caller对象的mCallback接口成员 调用callback()方法,完成回调.

Talk is cheap,show me the code!

现在就上代码来讲解,这是基于本例子的讲解。

public class Test{
         // 方法是fun
        public static void fun(Callbackinterface ci){
                ci.callbackfun();
        }

        //这就是接口
        public interface Callbackinterface{
                public void callbackfun();
        }
}

public static void main(){
        // 调用fun,传入接口对象并构造内部类
        Test.fun(new Callbackinterface(
                public void callbackfun(){
                        //你的实现
                }        
        )
        );
}

看完这个,大家可能还会比较模糊,没关系。我再讲一个实例:
一项工程由程序员A和B共同完成,分别负责不同的模块,模块之间有交叉,A和B可能用到对方的方法,这时需要进行回调。

假设我是程序员A,写了一个程序a:

public class Caller {

    private MyCallInterface mc;

    //构造函数
    public Caller() {
    }

    public setI(MyCallInterface mc) {
        this.mc = mc;
    }

    //Caller的调用方法
    public call() {
        mc.fuc();
    }
}

这里需要定义一个接口,以便程序员B根据我的定义编写程序实现接口

public interface MyCallInterface {
    public void fuc();
}

于是,程序员B只需要实现这个接口就能达到回调的目的了:

public class callee implements MyCallInterface {
    public void fuc() {
        //do something
    }
}

下面是调用过程:

public class callbacks {
    public static void main(String args[]) {
        Callee c1 = new Callee();
        Caller caller = new Caller();
        caller.setI(c1);
        caller.call();
    }
}

在以上代码中,caller是调用者,callee是被调用者,callbacks表示调用过程。

先产生了Callee对象(已经实现Caller提供的接口),利用这个callee对象产生的Caller对象则携带了一些信息(即与Callee对象的关联,因为Callee对象已经作为参数传入),所以Caller对象可以利用自己的call方法调用Callee的方法。——这就是整个回调过程。

看了这个例子,想必大家已经清楚了Java回调函数的机制了吧。

现在来总结一下,一般来说分为以下几步:
1.  声明回调函数的统一接口interface A,包含方法fuc();
2. 在调用类caller内将该接口设置为私有成员private A XXX;
3. 在caller内提供一个public方法,可以将外部“该接口A的实现类的引用”通过形参传给XXX;
4. caller的某个方法call()中会用到XXX.fuc()方法;
5. 在caller的实例中,将实现了A接口的对象的引用传给caller,后调用call()方法

2.Android的回调

Android中回调是用得非常多的。比如点击事件,Activity的生命周期等等,这里的回调大多更是一种触发机制,可以说回调也是一种触发吧。

例如Button是设置了接口,接口就是OnListener,在onClick中我们写入自己的实现,然后系统在事件被触发后调用。我们自己不会显式地去调用onClick方法。用户触发了该按钮的点击事件后,它会由Android系统来自动调用。

下面模拟一下Activity生命周期,基本都是回调函数在作用:
1. Activity接口

    //定义接口  
    public interface Activity{  
        //创建时调用的方法  
        public void onCreate();  
        //启动时调用的方法  
        public void onStart();  
        //销毁时调用的方法  
        public void onDestory();  
    }  

2. Activity接口的实现类MyActivity

    //定义一个类实现Activity接口  
    public void MyActivity implements Activity{  
        //实现创建方法,简单输出提示信息  
        @Override  
        public void onCreate(){  
            System.out.println("onCreate....");  
        }  

        //实现启动方法,简单输出提示信息  
        @Override  
        public void onStart(){  
            System.out.println("onStart....");  
        }  

        //实现销毁方法,简单输出提示信息  
        @Override  
        public void onDestory(){  
            System.out.println("onDestory....");  
        }  
    }  

3. 系统运行环境类AndroidSystem

    //系统运行环境类  
    public class AndroidSystem{  
        //定义创建常量  
        public static final int CREATE=1;  
        //定义启动常量  
        public static final int START=2;  
        //定义销毁常量  
        public static final int DESTORY=3;  

        //运行方法  
        public void run(Activity a,int state){  
            switch(state){  
                //创建  
                case CREATE:  
                    a.onCreate();  
                    break;  
                //启动  
                case START:  
                    a.onStart();  
                    break;  
                //销毁  
                case DESTORY:  
                    a.onDestory();  
                    break;  
            }  
        }  
    }  

测试类:

    //测试类  
    public class Test{  
        //主方法  
        public static void main(String[] args){  
            //实例化AndroidSystem  
            AndroidSystem system = new AndroidSystem();  

            //实例化MyActivity  
            Activity a = new MyActivity();  

            //创建  
            system.run(a,AndroidSystem.CREATE);  
            //启动  
            system.run(a,AndroidSystem.START);  
            //销毁  
            system.run(a,AndroidSystem.DESTORY);  
        }  
    }  

通过上述代码我们可以看出,接口(系统框架)是系统提供的,接口的实现是用户实现的。这样可以达到接口统一,实现不同。系统通过在不同的状态“回调”我们的实现类,来达到接口和实现的分离。

这里引用其它人博客的一个事例吧:

让我们从一个小故事开始。

某天,我打电话向你请教问题,当然是个难题,你一时想不出解决方法,我又不能拿着电话在那里傻等,于是我们约定:等你想出办法后打手机通知我,这样,我就挂掉电话办其它事情去了。过了XX分钟,我的手机响了,你兴高采烈的说问题已经搞定,应该如此这般处理。

OK,这个故事我们先告一段落,其实,这就是一个典型的回调过程。

而在程序代码中,则可以抽象成以下这张图的形式:

这里写图片描述

C不会自己调用b,C提供b的目的就是让S来调用它,而且C不得不提供。S并不知道C提供的b是什么,因此S会约定b的接口规范(函数原型),然后由C提前通过S的一个函数r告诉S自己将要使用b函数(即注册),比如注册监听器就是其中一种典型。其中r为注册函数。
对上图的一个完善是这样的:
这里写图片描述

Android中还有很多其它的消息回调机制,我整理下后面会和大家分享。

你可能感兴趣的:(Android之路)