關於回調函數的理解

回調函數


更新:2017-1-22


這裏寫圖片描述

網上關於回調函數的例子很多。以下下是我的理解:

  • 神話版:調用,回調。
  • 直述版:A讓B做某事,B做着做着發現:哎呀,不對呀,這事具體應該怎麼做呀?於是,回調A中詢問事件具體的實現形式。然後完成事件。——以同步回調的角度(或者理解:這事我做完了接下該你A來做了,於是回調A的方法——以異步回調的角度)
  • 抽象版:首先A有某事要完成,分爲動作①和動作②。A讓B做某事的動作①(在B中實現動作①),B做完之後回調A 某事中的動作②(在A中實現,A懶得做了,提供方法想讓B給他完成)。完成整個某事。(簡之:a調用了b的方法,b開始執行,b執行完了,再調用a的方法。)
    *注意:A調用B,B執行完後返回A → 只是簡單的調用,沒有涉及到回調,即沒有回調函數的實現。
  • 具體版:有A和B兩類(A看成應用程序,B看成系統),A調用B的方法Bf實現動作(A可以在Bf傳入相關信息,★其中包括A的引用)。Bf的方法在執行完成後,因爲有了A的引用,可以回調A的Af方法。Af方法就是回調函數,用來展示,或者說完成某事。
  • 終極版: 上述在回調函數中直接傳入對象的引用。產生的問題(Bf方法的形參裏有A的引用):①暴露了對象,即傳入了A的引用(B系統得到了A的引用,萬一B是競爭對手呢,不安全);②增加了耦合性,每有一個新的A出現需要重寫Bf方法(因爲形參需要改變)。終極大招:接口方式的回調方法。——首先定義接口,A1、A2、A3。。。可以各自實現接口,相當於有不同的動作②(此時的Af是基於接口的實現方法)。A調用B的Bf方法完成動作①後,Bf回調A中方法Af(Bf的形參現在是接口,B幹不了壞事了)。
  • (彩蛋)實用主義:匿名內部類。直接在方法Af實現接口。

eg:https://www.zhihu.com/question/19801131/answer/26586203


同步與異步

同步和異步關注的是消息通信機制 (synchronous communication/ asynchronous communication)

  • 所謂同步,就是在發出一個調用時,在沒有得到結果之前,該調用就不返回。但是一旦調用返回,就得到返回值了。
    換句話說,就是由調用者主動等待這個調用的結果。

  • 異步則是相反,調用在發出之後,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個異步過程調用發出後,調用者不會立刻得到結果。而是在調用發出後,被調用者通過狀態、通知來通知調用者,或通過回調函數處理這個調用。

  • 異步回調
    異步回調有點像中斷調用。在A中開線程調用B,然後做自己的事。等B處理完回調A。

  • 同步回調
    A一直等B的回調。

實現場景

例1:打個比方,有一家旅館提供叫醒服務,但是要求旅客自己決定叫醒的方法。可以是打客房電話,也可以是派服務員去敲門,睡得死怕耽誤事的,還可以要求往自己頭上澆盆水。這裏,“叫醒”這個行爲是旅館提供的,相當於庫函數,但是叫醒的方式是由旅客決定並告訴旅館的,也就是回調函數。而旅客告訴旅館怎麼叫醒自己的動作,也就是把回調函數傳入庫函數的動作,稱爲登記回調函數
eg:https://www.zhihu.com/question/19801131/answer/27459821
來源:知乎
著作權歸作者所有,轉載請聯繫作者獲得授權。
解釋了回調函數在實際中的意義。


例2:你到一個商店買東西,剛好你要的東西沒有貨,於是你在店員那裏留下了你的電話,過了幾天店裏有貨了,店員就打了你的電話,然後你接到電話後就到店裏去取了貨。在這個例子裏,你的電話號碼就叫回調函數,你把電話留給店員就叫登記回調函數,店裏後來有貨了叫做觸發了回調關聯的事件,店員給你打電話叫做調用回調函數,你到店裏去取貨叫做響應回調事件。回答完畢。

作者:常溪玲
鏈接:https://www.zhihu.com/question/19801131/answer/13005983
來源:知乎
著作權歸作者所有,轉載請聯繫作者獲得授權。
異步回調。A:我;B:店員。買東西事件分爲兩個行動,行動①:找貨,A調用B執行;行動②:打電話,B回調A的電話號碼。


例3:一個經典例子讓你徹徹底底理解java回調機制
來源:http://blog.csdn.net/xiaanming/article/details/8703708/

3.1 有一天小王遇到一個很難的問題,問題是“1 + 1 = ?”,就打電話問小李,小李一下子也不知道,就跟小王說,等我辦完手上的事情,就去想想答案,小王也不會傻傻的拿着電話去等小李的答案吧,於是小王就對小李說,我還要去逛街,你知道了答案就打我電話告訴我,於是掛了電話,自己辦自己的事情,過了一個小時,小李打了小王的電話,告訴他答案是2
異步回調。A:小王;B:小李。行動①:算出答案,A調用B執行;行動②:解決問題,B回調Asolve(String result)方法。
3.2 Android View的點擊方法onclick()。onclick()是一個回調方法。同步回調。

  • 匿名內部類形式:匿名內部類必須實現一個接口或繼承一個父類,但最多隻能實現/繼承一個
public class MainActivity extends Activity {  
    //不需要調用接口

    private Button button;  

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        button =(Button)findViewById(R.id.button1);  

        /** 
         * 直接實現接口→相當於this引用 。即調用B的Bf方法,並且new相當於傳入自身接口參數
         */  
        button.setOnClickListener(new View.OnClickListener() {
            /** 
             * 實現接口中的方法(回調函數)
             */  
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
            }
        });
    }
}  
  • 內部類形式
public class MainActivity extends Activity {  
    //不需要調用接口

    private Button button;  

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        button =(Button)findViewById(R.id.button1);  

        /** 
         * 相當於調用B的Bf方法,傳入自身參數 
         */  
        button.setOnClickListener(new MyClickListener)
    }
    /** 
     * 內部類,實現接口 
     */  
    class MyClickListener implements View.OnClickListener{
        /** 
         * 實現接口中的方法(回調函數)
         */  
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
        }
    }
}  
  • 頂級類形式:類本身作爲事件監聽器
public class MainActivity extends Activity implements OnClickListener{  //調用接口

    private Button button;  

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        button =(Button)findViewById(R.id.button1);  

        /**
         * 相當於調用B的Bf方法 
         * this(傳入的參數):引用自身,相當於A
         */  
        button.setOnClickListener(this);  
    }  

    /** 
     * 用戶點擊Button時調用的回調函數,即實現接口裏的方法
     */  
    @Override  
    public void onClick(View v) {  
        Toast.makeText(getApplication(), "OnClick", Toast.LENGTH_LONG).show();  
    }  
}  
    2.

引用資料:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章