Java(Android)回呼函數詳解

來源:互聯網
上載者:User

標籤:

一、前言

本周有位入行開發不久的朋友問我回調究竟是個什麼概念,在網上看了很多的回呼函數解釋,但是越看越亂。雖然回呼函數這個梗已經不新鮮了,這裡還是用書面的形式記錄下。

如果有瞭解的,就無需再看。

二、概念

概念上,這裡引用百度百科的解釋,如下:

回呼函數就是一個通過函數指標調用的函數。如果你把函數的指標(地址)作為參數傳遞給另一個函數,當這個指標被用來調用其所指向的函數時,我們就說這是回呼函數。回呼函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應。

百度百科的定義就是上面這樣的,它提到了函數指標這個概念,函數指標一般是C/C++的專有名詞。Java中也是有這個概念的,只是我們把它叫做引用,淡化了函數指標的概念,使用也更加簡單。

這個概念的定義,看上去是有點繞,並且不容易理解。網上有很多的對回呼函數的說明,比如,A類調用B類的方法B1,B類又調用A類的方法A1之類。這樣的說法,其實看的也很迷茫。

因此,會在下文中對回呼函數做一個層次分明的解釋。

三、元素

根據概念,我們知道一個回呼函數的調用流程是需要以下三個元素,並分別給它們一個名字:

1、回呼函數本身——回呼函數;

2、回呼函數作為參數傳入的函數——中間函數;

3、調用者(調用函數)——調用函數。

根據以上的命名,回呼函數的流程就是:

(1)將回呼函數的引用,傳入到中間函數(這個也可以稱之為回呼函數的註冊/訂閱)。

(2)調用函數調用中間函數,觸發回呼函數的事件。

純文字說明可能沒有感覺,這裡我們引入一個很簡單的例子,來描述這一流程:

首先,你需要一個回呼函數:

package com.callback;public class Callback {public void call(){System.out.println("我是一個回呼函數,當我被列印出來的時候,說明回呼函數被觸發了");}}

其次,再來一個中間函數:

package com.callback;public class Middle {//參數是回呼函數所在類的引用public void mid(Callback callback){//觸發回呼函數callback.call();}}

最後,是調用函數:

package com.callback;public class Main {/** * @param args */public static void main(String[] args) {         Middle m=new Middle();         //回呼函數註冊,將Callback的引用傳入中間函數         m.mid(new Callback());         }}

運行一下,你就可以看到列印結果:

我是一個回呼函數,當我被列印出來的時候,說明回呼函數被觸發了

以上是一個簡單例子,在該例子中,用最簡方式模仿了回呼函數的調用過程。但日常中我們是不會或者很少這麼用的,因為該例子沒有很好的表現出回呼函數的作用。

回呼函數有什麼作用?在百度百科上有一段對它們意義的說明:

1、因為可以把調用者與被調用者分開,所以調用者不關心誰是被調用者。它只需知道存在一個具有特定原型和限制條件的被調用函數。

2、回調可用於通知機制。

3、這一設計允許了底層代碼調用在高層定義的子程式。

簡單的說,可以用於解耦、通知以及其他。

為了完整說明回呼函數的作用,我們再原來的例子上,做個擴充,引入介面。擴充的還是上面的例子,引入介面:

新增介面:

package com.callback;public interface CallbackInterface {public void call();}

原有的回呼函數,實現上面的介面:

package com.callback;public class Callback implements CallbackInterface{public void call() {// TODO Auto-generated method stubSystem.out.println("我是一個回呼函數,當我被列印出來的時候,說明回呼函數被觸發了");}}

中間函數的參數,做以下修改(修改為介面):

package com.callback;public class Middle {//參數是回呼函數所在類的引用public void mid(CallbackInterface callback){//觸發回呼函數callback.call();}}

最後是調用函數:

package com.callback;public class Main {/** * @param args */public static void main(String[] args) {         Middle m=new Middle();         //回呼函數註冊         CallbackInterface ifsImpl=new Callback();         m.mid(ifsImpl);}}
對比兩個例子,在後面這個例子中,引入介面,實現了:調用函數、中間函數與回呼函數的解耦。底層函數對高層函數的調用。通知機制。


四、回呼函數作為參數傳入的方法

這是一個小細節,設計人員可以仿照依賴注入的三種方式,來實現回呼函數的參數傳入。

1、建構函式中傳入;

2、用set方式傳入;

3、直接將函數(介面)作為參數傳入;

例子中就是第三種方式。

到此,回呼函數的介紹就基本結束了。但是,上面的兩個例子和我們實際接觸的還是有那麼一些差距。

在看完上面的例子後,對回調有了比較深的認識。現在,已經可以理論聯絡實際了。

也舉一個日常用的很多的情境:Android中的按鈕點擊事件(這也是應用最廣泛的一個回呼函數)。


五、Andriod按鈕點擊事件的類比對比

1、新開一個Android工程,我們做一個真實的按鈕點擊事件,如下:

//原始        Button btn=(Button)findViewById(R.id.btn);        btn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubSystem.out.println("按鈕被點擊了-原始");}});

2、再根據前面我們自己的分析,做一個按鈕點擊的回呼函數事件:

也首先是一個回呼函數:

package com.example.callbackandroid;public interface MyOnClickListener {//回呼函數public void onClick();}

中間函數:

package com.example.callbackandroid;public class MyButton {private MyOnClickListener listener;//回呼函數註冊/訂閱/登記public void setOnclickListener(MyOnClickListener listener){this.listener=listener;}public void doOnclick(){listener.onClick();}}

調用函數:

 //類比        MyButton mButton=new MyButton();        mButton.setOnclickListener(new MyOnClickListener() {@Overridepublic void onClick() {// TODO Auto-generated method stubSystem.out.println("按鈕被點擊了-原始");}});                mButton.doOnclick();

對比原始的android點擊事件以及我們類比的android點擊事件,發現有一點區別:原始的android點擊不需要沒有調用doOnclick事件,沒有調用函數??

實際上,原始的android點擊事件是有調用函數的,只是不需要寫在這裡而已。如果有看過Android的onClick事件(事件分發)源碼的朋友,會發現:在源碼中,當android系統檢測到該View的ACTION_UP的操作時,會調用performClick()這個函數,而這個函數的內容如下:

public boolean performClick() {    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);    if (mOnClickListener != null) {        playSoundEffect(SoundEffectConstants.CLICK);        mOnClickListener.onClick(this);        return true;    }    return false;}
它的調用函數,是在這裡實現的。只要mOnClickListener不為null(這個就是通過我們setOnClickListener來賦值的),那麼onClick就會被調用。

因此,它和類比點擊原理其實是一樣的。

到這裡,回呼函數的分析就告一段落了。

下一段落,主要是一個概念的整理。

六、回呼函數與同步、非同步

在真正使用回呼函數的時,我們經常會接觸到非同步回調、非同步呼叫、同步調用這些詞。這裡簡單說下概念,以免混亂,作為結尾。

同步調用:
這個是日常使用最頻繁的一種調用方法,這是一個阻塞調用,如你調用一個方法,等待這個方法返回,或者執行完畢。

非同步呼叫:

這個在android中也使用頻繁,非阻塞調用,如你調用一個方法,無需等這個方法返回,即往下執行其他動作。

非同步回調:

這個是非同步+回調的形式。





Java(Android)回呼函數詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.