android中的廣播機(jī)制回調(diào)和接口回調(diào)

android中有很多需要數(shù)據(jù)交互的部分,交互的方式也有很多種不同,四大組件各有各的方法, 今天主要是談?wù)勱P(guān)于回調(diào)部分的看法。

首先介紹一下什么是回調(diào)函數(shù):

回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個函數(shù),當(dāng)這個指針被用來調(diào)用其所指向的函數(shù)時,我們就說這是回調(diào)函數(shù)。

所以說回調(diào)函數(shù)只是觸發(fā),回調(diào)函數(shù)不是由該函數(shù)的實現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時由另外的一方調(diào)用的,用于對該事件或條件進(jìn)行響應(yīng)。

舉個栗子:

朋友過生日,你打電話給蛋糕店去預(yù)定蛋糕,蛋糕店說做好了給你打電話,你說OK,給我打了電話我去取蛋糕,然后你把電話留給了蛋糕店。

分解一下動作:包括你的和蛋糕店的。
你的動作:預(yù)定蛋糕(業(yè)務(wù)邏輯),留電話(登記回調(diào)函數(shù)),取蛋糕(響應(yīng)回調(diào)函數(shù))
蛋糕店的動作:做蛋糕(觸發(fā)回調(diào)函數(shù)業(yè)務(wù)邏輯),給你打電話(調(diào)用回調(diào)函數(shù))。

那么以上就是一個基本的回調(diào)函數(shù)部分和內(nèi)容。

android中的廣播機(jī)制回調(diào):

類比一下:

我的應(yīng)用想要獲取驗證碼,當(dāng)系統(tǒng)來短信的時候通知應(yīng)用,應(yīng)用要讀取短信內(nèi)容,用來代填驗證碼

應(yīng)用要做的:代填驗證碼(業(yè)務(wù)邏輯),約定通知方式(登記回調(diào)函數(shù)),讀取短信內(nèi)容(響應(yīng)回調(diào)函數(shù))
系統(tǒng)要做的:收到短信(觸發(fā)回調(diào)函數(shù)業(yè)務(wù)邏輯),通知應(yīng)用(調(diào)用回調(diào)函數(shù))

在安卓中這個問題一般都是用廣播來解決的,約定通知方式(注冊監(jiān)聽系統(tǒng)收到廣播的action),讀取短信內(nèi)容(也就是在自己注冊的廣播中進(jìn)行相關(guān)操作),以下是代碼:


//初始化廣播
private SMSBroadcastReceiver receiver = new SMSBroadcastReceiver();

 //注冊廣播
 private void registerSmsReceiver(){
     IntentFilter filter = new IntentFilter();
     filter.addAction("android.provider.Telephony.SMS_RECEIVED");
     registerReceiver(receiver,filter);
     receiver.setSMSmessageListener(this);
 }
 
 //解除注冊廣播
 private void unregisterSmsReceiver(){
     unregisterReceiver(receiver);
 }
 
 
 //廣播中獲取短信內(nèi)容的相關(guān)邏輯(業(yè)務(wù)邏輯)
 public class SMSBroadcastReceiver extends BroadcastReceiver {

 private SMSmessage smsmessage;
 @Override
 public void onReceive(Context context, Intent intent) {
     Object[] pduses= (Object[])intent.getExtras().get("pdus");
     for(Object pdus: pduses){
         byte[] pdusmessage = (byte[])pdus;
         SmsMessage sms = SmsMessage.createFromPdu(pdusmessage);
         String mobile = sms.getOriginatingAddress();//發(fā)送短信的手機(jī)號碼
         String content = sms.getMessageBody(); //短信內(nèi)容
     }
 }
 
 }

以上我們只做了客戶端部分的代碼,另一半是系統(tǒng)幫助我們完成的,那么以下是我們獨立通過廣播去完成一項操作

當(dāng)B應(yīng)用登錄(成功/失?。┑臅r候,B告知A自己的登陸狀態(tài),A應(yīng)用彈出toast告知用戶B應(yīng)用登陸完成

A應(yīng)用要做的:彈出toast(業(yè)務(wù)邏輯),約定通知方式(登記回調(diào)函數(shù)),獲取登陸狀態(tài)(響應(yīng)回調(diào)函數(shù))
B應(yīng)用要做的:登陸操作及其結(jié)果(觸發(fā)回調(diào)函數(shù)業(yè)務(wù)邏輯),通知A應(yīng)用(調(diào)用回調(diào)函數(shù)),以下是代碼:

  • ** A應(yīng)用:**
   //初始化廣播
   ActivationResultReceiver receiver = new ActivationResultReceiver();
   
   
    //注冊廣播
    private void registerActivationResultReceiver(){
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.login.ACTIVATION_FINISH_INFO");
        registerReceiver(receiver, intentFilter);
    }

   
    //解除注冊廣播
    private void unregisterActivationResultReceiver(){
        unregisterReceiver(receiver);
    }
    
    //獲取登陸狀態(tài)(響應(yīng)回調(diào)函數(shù))
    public class ActivationResultReceiver extends BroadcastReceiver {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent != null && intent.getAction().equals("com.login.ACTIVATION_FINISH_INFO")){
            SharedPreferences sharedPreferences = context.getSharedPreferences("ACTIVATION_STATUS", Context.MODE_WORLD_READABLE);
            Editor editor = sharedPreferences.edit();//獲取編輯器
            if(intent.getStringExtra("status").equals("success")){
                //彈出toast(業(yè)務(wù)邏輯)
                Toast.makeText(context, "激活成功", Toast.LENGTH_SHORT).show();
                editor.putBoolean("activation_status", true);
            }else if(intent.getStringExtra("status").equals("failed")){
                //彈出toast(業(yè)務(wù)邏輯)
                Toast.makeText(context, "激活失敗" + intent.getIntExtra("activateErrorCode",0), Toast.LENGTH_SHORT).show();
                editor.putBoolean("activation_status", false);
            }else {
                editor.putBoolean("activation_status", false);
            }
            editor.commit();
        }
    }
}
  • ** B應(yīng)用:**
    //登陸操作及其結(jié)果(觸發(fā)回調(diào)函數(shù)業(yè)務(wù)邏輯)
    public static void ActivationResult(Context context,Boolean result,ActivationException exception){
                if(result){
                    sendActivateResultReceiver(true,exception,context);
                }else{
                    sendActivateResultReceiver(false,exception,context);
                }
    }
    //通知A應(yīng)用(調(diào)用回調(diào)函數(shù))
    private static void sendActivateResultReceiver(Boolean result,ActivationException exception,Context context){
        Intent intent = new Intent();
        intent.setAction("com.login.ACTIVATION_FINISH_INFO");
        if(result){
            intent.putExtra("status", "success");
        }else{
            intent.putExtra("status", "failed");
            if(exception != null){
                intent.putExtra("activateErrorCode", exception.activateErrorCode);
                intent.putExtra("activateErrorMessage", exception.activateErrorMessage);                
            }
        }
        intent.setPackage(RECEIVER_PACKAGENAME);
        context.sendBroadcast(intent);
    }

也就是說在廣播回調(diào)方式中包括幾個條件:

  1. 客戶端注冊廣播,聲明相關(guān)的觸發(fā)條件(action)
  2. 客戶端完成接收廣播以后的相關(guān)業(yè)務(wù)邏輯(onRecevier方法內(nèi)部)
  3. 服務(wù)端在需要的觸發(fā)時機(jī)發(fā)送廣播,同時也可以通過intent將一些數(shù)據(jù)傳給客戶端
  4. 廣播的內(nèi)部實現(xiàn)(android API已經(jīng)幫我們做好了)

android中的接口回調(diào):

關(guān)于handler內(nèi)部就是接口實現(xiàn),將在以后提及

繼續(xù)類比一下:

舉一個最簡單的例子,按鈕的點擊事件,就是一個接口回調(diào)事件
我們自定義應(yīng)用本身要做的事情很簡答,第一就是調(diào)用setOnClickListener()這個方法(登記回調(diào)函數(shù)),
第二就是實現(xiàn)OnClickLister接口的onClick(View v)方法(響應(yīng)回調(diào)函數(shù)),在其中添加的方法就是自己的業(yè)務(wù)邏輯
而系統(tǒng)幫我們做了(觸發(fā)回調(diào)函數(shù)業(yè)務(wù)邏輯)(調(diào)用回調(diào)函數(shù))

    //調(diào)用setOnClickListener()這個方法(登記回調(diào)函數(shù))
    Button activation;
    activation.setOnClickListener(new View.OnClickListener() {
    
            //實現(xiàn)OnClickLister接口的onClick(View v)方法(響應(yīng)回調(diào)函數(shù))
            @Override
            public void onClick(View v) {

            }
    });

同樣我們接著自己構(gòu)造一個接口去完整的實現(xiàn)該功能,那么現(xiàn)在大量使用這個方式的就是在應(yīng)用登錄時候的UI頁面刷新上了。
一般登錄都是從點擊登錄按鈕開始,將用戶名密碼等信息經(jīng)過拼接加密,發(fā)送給服務(wù)端,服務(wù)端經(jīng)過驗證返回errorCode和errorMessage
當(dāng)客戶端收到以后,根據(jù)errorCode的不同對UI進(jìn)行不同的變化操作,這個就是典型的回調(diào)式操作了

構(gòu)造接口LogInInterface

** UI線程要做的:調(diào)用setCallBack()(登記回調(diào)函數(shù)),實現(xiàn)LogInInterface接口(響應(yīng)回調(diào)函數(shù))根據(jù)不同的errorCode進(jìn)行不同的變化(業(yè)務(wù)邏輯)

后臺網(wǎng)絡(luò)線程要做的:,setCallBack()(觸發(fā)回調(diào)函數(shù)業(yè)務(wù)邏輯),callBack.callBackByEnterResult();(調(diào)用回調(diào)函數(shù))

  • UI線程:
        //登記回調(diào)函數(shù)
    JITTFCardManager.getInstance().setCallBack(context, new LogInInterface() {
            //響應(yīng)回調(diào)函數(shù)
            @Override
            public void callBackByEnterResult() {
                //內(nèi)部是業(yè)務(wù)邏輯
            }

            @Override
            public void callBackByRetry() {
               //內(nèi)部是業(yè)務(wù)邏輯
            }
        });
  • 后臺線程:
    public interface LogInInterface {
    
        public void callBackByEnterResult();
    
        public void callBackByRetry();
    }
    
    //觸發(fā)回調(diào)函數(shù)業(yè)務(wù)邏輯
    public void setCallBack(Context context, LogInInterface callBack) {
        this.callBack = callBack;
    }
   
   
    if (result) {
        Toast.makeText(context, "身份認(rèn)證成功", Toast.LENGTH_SHORT).show();
        //調(diào)用回調(diào)函數(shù)
        callBack.callBackByEnterResult();
    } else {
        Toast.makeText(context, "身份認(rèn)證失敗", Toast.LENGTH_SHORT).show();
        //調(diào)用回調(diào)函數(shù)
        callBack.callBackByRetry();
    }           

最后來對比一下廣播回調(diào)和接口回調(diào):

首先因為都是觸發(fā)式回調(diào),實現(xiàn)了觀察者模式,對于代碼的復(fù)用和耦合度的降低都是有顯著貢獻(xiàn)的。

廣播機(jī)制回調(diào):可以跨進(jìn)程調(diào)用,廣播也是安卓跨進(jìn)程通信的重要組成部分,但是同樣,廣播機(jī)制回調(diào)是最慢的,而且自我構(gòu)造的進(jìn)程間廣播容易被國產(chǎn)的一些系統(tǒng)屏蔽掉,這點也比較頭疼

接口回調(diào):線程間通信的方式,速度快,構(gòu)造起來也比較簡潔,屬于java本身的一種回調(diào)方式(安卓官方提供的handler機(jī)制內(nèi)部其實就是callback接口回調(diào))

速度上來說:接口 》 handler 》廣播 適用性來說廣播最好

而關(guān)于回調(diào)及線程間的交互,安卓官方最推薦的一種就是handler的方式,也是安卓api在接口基礎(chǔ)上發(fā)展的方式,下一篇將來談?wù)刪andler。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,007評論 25 709
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,551評論 19 139
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 12,374評論 6 13
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,669評論 18 399
  • 2016.5.15 周日 雨 昨天下午我收到了當(dāng)當(dāng)網(wǎng)給我送的這本書,我就迫不急待的拿著它看了起來,我從簡書上看到好...
    tina_tina_tina閱讀 360評論 0 0

友情鏈接更多精彩內(nèi)容