天天看點

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=;  
        //定義啟動常量  
        public static final int START=;  
        //定義銷毀常量  
        public static final int DESTORY=;  

        //運作方法  
        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,這個故事我們先告一段落,其實,這就是一個典型的回調過程。

而在程式代碼中,則可以抽象成以下這張圖的形式:

Android接口回調,最簡單的了解方式

C不會自己調用b,C提供b的目的就是讓S來調用它,而且C不得不提供。S并不知道C提供的b是什麼,是以S會約定b的接口規範(函數原型),然後由C提前通過S的一個函數r告訴S自己将要使用b函數(即注冊),比如注冊監聽器就是其中一種典型。其中r為注冊函數。

對上圖的一個完善是這樣的:

Android接口回調,最簡單的了解方式

Android中還有很多其它的消息回調機制,我整理下後面會和大家分享。

繼續閱讀