BroadcastReceiver 詳細(xì)解析

廣播是一種廣泛運(yùn)用的在應(yīng)用程序之間傳輸信息的機(jī)制,主要用來監(jiān)聽系統(tǒng)或者應(yīng)用發(fā)出的廣播信息,然后根據(jù)廣播信息作為相應(yīng)的邏輯處理,也可以用來傳輸少量、頻率低的數(shù)據(jù)。

在實現(xiàn)開機(jī)啟動服務(wù)和網(wǎng)絡(luò)狀態(tài)改變、電量變化、短信和來電時通過接收系統(tǒng)的廣播讓應(yīng)用程序作出相應(yīng)的處理。

BroadcastReceiver 自身并不實現(xiàn)圖形用戶界面,但是當(dāng)它收到某個通知后, BroadcastReceiver 可以通過啟動 Service 、啟動 Activity 或是 NotificationMananger 提醒用戶。

使用廣播的注意事項

當(dāng)系統(tǒng)或應(yīng)用發(fā)出廣播時,將會掃描系統(tǒng)中的所有廣播接收者,通過 action 匹配將廣播發(fā)送給相應(yīng)的接收者,接收者收到廣播后將會產(chǎn)生一個廣播接收者的實例,執(zhí)行其中的 onReceiver() 這個方法;特別需要注意的是這個實例的生命周期只有10秒,如果10秒內(nèi)沒執(zhí)行結(jié)束 onReceiver() ,系統(tǒng)將會報錯。在 onReceiver() 執(zhí)行完畢之后,該實例將會被銷毀,所以不要在 onReceiver() 中執(zhí)行耗時操作,也不要在里面創(chuàng)建子線程處理業(yè)務(wù)(因為可能子線程沒處理完,接收者就被回收了,那么子線程也會跟著被回收掉);正確的處理方法就是通過 intent 調(diào)用 Activity 或者 Service 處理業(yè)務(wù)。

BroadcastReceiver的注冊

BroadcastReceiver 的注冊方式有且只有兩種,一種是靜態(tài)注冊(推薦使用),另外一種是動態(tài)注冊,廣播接收者在注冊后就開始監(jiān)聽系統(tǒng)或者應(yīng)用之間發(fā)送的廣播消息。

下面通過例子看一下兩種注冊方式,先定義一個接收短信的 BroadcastReceiver 類:

public class MyBroadcastReceiver extends BroadcastReceiver {
    // action 名稱
    String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED" ;
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals( SMS_RECEIVED )) {
            // 一個receiver可以接收多個action的,即可以有
            // 多個intent-filter,需要在 onReceive
            // 里面對 intent.getAction(action name) 進(jìn)行判斷。
            ...
        }
    }
}
  • 靜態(tài)注冊

    在 AndroidManifest.xml 的 application 里面定義 receiver 并設(shè)置要接收的action。

    < receiver android:name = ".MyBroadcastReceiver" > 
        < intent-filter android:priority = "777" >       
            <action android:name = "android.provider.Telephony.SMS_RECEIVED" />
        </ intent-filter > 
    </ receiver >
    

    這里的 priority 取值是 -1000 到 1000 ,值越大優(yōu)先級越高,同時注意加上系統(tǒng)接收短信的限權(quán)。

    靜態(tài)注冊的廣播接收者是一個常駐在系統(tǒng)中的全局監(jiān)聽器,當(dāng)你在應(yīng)用中配置了一個靜態(tài)的 BroadcastReceiver ,安裝了應(yīng)用后而無論應(yīng)用是否處于運(yùn)行狀態(tài),廣播接收者都是已經(jīng)常駐在系統(tǒng)中了。同時應(yīng)用里的所有 receiver 都在清單文件里面,方便查看。要銷毀掉靜態(tài)注冊的廣播接收者,可以通過調(diào)用 PackageManager 將 Receiver 禁用。

  • 動態(tài)注冊

    在 Activity 中聲明 BroadcastReceiver 的擴(kuò)展對象,在 onResume 中注冊,onPause 中卸載.

    public class MainActivity extends Activity {
        MyBroadcastReceiver receiver;
    
        @Override
        protected void onResume() {
            // 動態(tài)注冊廣播 (代碼執(zhí)行到這才會開始監(jiān)聽廣播消息,并對廣播消息作為相應(yīng)的處理)
            receiver = new MyBroadcastReceiver();
            IntentFilter intentFilter = new IntentFilter( "android.provider.Telephony.SMS_RECEIVED" );
            registerReceiver( receiver , intentFilter); 
            super.onResume();
        }
    
        @Override
        protected void onPause() { 
            // 撤銷注冊 (撤銷注冊后廣播接收者將不會再監(jiān)聽系統(tǒng)的廣播消息)
            unregisterReceiver(receiver);
            super.onPause();
        }
    }
    
  • 靜態(tài)注冊和動態(tài)注冊的區(qū)別

    1. 靜態(tài)注冊的廣播接收者一經(jīng)安裝就常駐在系統(tǒng)之中,不需要重新啟動喚醒接收者;動態(tài)注冊的廣播接收者隨著應(yīng)用的生命周期,由 registerReceiver 開始監(jiān)聽,由 unregisterReceiver 撤銷監(jiān)聽,如果應(yīng)用退出后,沒有撤銷已經(jīng)注冊的接收者應(yīng)用應(yīng)用將會報錯。

    2. 當(dāng)廣播接收者通過 intent 啟動一個 activity 或者 service 時,如果 intent 中無法匹配到相應(yīng)的組件。動態(tài)注冊的廣播接收者將會導(dǎo)致應(yīng)用報錯,而靜態(tài)注冊的廣播接收者將不會有任何報錯,因為自從應(yīng)用安裝完成后,廣播接收者跟應(yīng)用已經(jīng)脫離了關(guān)系。

發(fā)送廣播主要類型

  • 普通廣播

    普通廣播是完全異步的,可以在同一時刻(邏輯上)被所有接收者接收到,所有滿足條件的 BroadcastReceiver 都會隨機(jī)地執(zhí)行其 onReceive() 方法。

    同級別接收是先后是隨機(jī)的;級別低的收到廣播;消息傳遞的效率比較高,并且無法中斷廣播的傳播。

    Intent intent = new Intent("android.provider.Telephony.SMS_RECEIVED"); 
    //通過intent傳遞少量數(shù)據(jù)
    intent.putExtra("data", "finch"); 
    // 發(fā)送普通廣播
    sendBroadcast(Intent);
    
  • 有序廣播

    有序廣播通過 Context.sendOrderedBroadcast() 來發(fā)送,所有的廣播接收器優(yōu)先級依次執(zhí)行,廣播接收器的優(yōu)先級通過 receiver 的 intent-filter 中的 android:priority 屬性來設(shè)置,數(shù)值越大優(yōu)先級越高。

    當(dāng)廣播接收器接收到廣播后,可以使用 setResult() 函數(shù)來結(jié)果傳給下一個廣播接收器接收,然后通過 getResult() 函數(shù)來取得上個廣播接收器接收返回的結(jié)果。

    當(dāng)廣播接收器接收到廣播后,也可以用 abortBroadcast() 函數(shù)來讓系統(tǒng)攔截下來該廣播,并將該廣播丟棄,使該廣播不再傳送到別的廣播接收器接收。

  • 本地廣播

    在 API21 的 Support v4 包中新增本地廣播,也就是 LocalBroadcastManager 。由于之前的廣播都是全局的,所有應(yīng)用程序都可以接收到,這樣就會帶來安全隱患,所以我們使用 LocalBroadcastManager 只發(fā)送給自己應(yīng)用內(nèi)的信息廣播,限制在進(jìn)程內(nèi)使用。

    它的用法很簡單,只需要把調(diào)用 context 的 sendBroadcast、registerReceiver、unregisterReceiver 的地方換為 LocalBroadcastManager.getInstance(Context context)中對應(yīng)的函數(shù)即可。

    這里創(chuàng)建廣播的過程和普通廣播是一樣的過程,這里就不過多介紹了

  • 系統(tǒng)廣播

    當(dāng)然系統(tǒng)中也會有很多自帶的廣播,當(dāng)符合一定條件時,系統(tǒng)會發(fā)送一些定義好的廣播,比如:重啟、充電、來電電話等等。我們可以通過action屬性來監(jiān)聽我們的系統(tǒng)廣播,創(chuàng)建廣播的過程和普通廣播是一樣的過程,這里就不過多介紹了。

    常用的廣播action屬性有:

    • 屏幕被關(guān)閉之后的廣播:Intent.ACTION_SCREEN_OFF

    • 屏幕被打開之后的廣播:Intent.ACTION_SCREEN_ON

    • 充電狀態(tài),或者電池的電量發(fā)生變化:Intent.ACTION_BATTERY_CHANGED

    • 關(guān)閉或打開飛行模式時的廣播:Intent.ACTION_AIRPLANE_MODE_CHANGED

    • 表示電池電量低:Intent.ACTION_BATTERY_LOW

    • 表示電池電量充足,即電池電量飽滿時會發(fā)出廣播:Intent.ACTION_BATTERY_OKAY

    • 按下照相時的拍照按鍵(硬件按鍵)時發(fā)出的廣播:Intent.ACTION_CAMERA_BUTTON

    值得注意的是,隨著系統(tǒng)版本的提升,很多系統(tǒng)廣播已經(jīng)不再被支持,如果你需要使用哪個系統(tǒng)廣播,最好看看最新版本的支持情況。

最后編輯于
?著作權(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)容

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