本文主要介紹BroadcastReceiver的概念、使用、生命週期、安全性、分類、特殊的BroadcastReceiver(本地、粘性、有序、粘性有序廣播)。代碼地址BroadcastReceiverDemo@GoogleCode
1、概念介紹及兩種註冊方式的區別
BroadcastReceiver作為Android四大組件之一,不像Activity,沒有可顯示的介面。BroadcastReceiver包括兩個概念,廣播寄件者和廣播接收者(Receiver),這裡的廣播實際就是指Intent,程式可以自己發送廣播自己接收,也可以接受系統或其他應用的廣播或是發送廣播給其他應用程式。
寄件者可以通過類似Context.sendBroadcast介面發送廣播,接收者通過Context.registerReceiver()動態註冊或在AndroidManifest.xml檔案中通過<receiver>標籤靜態註冊,註冊完成後,當寄件者發送某個廣播時系統會將發送的廣播(Intent)與系統中所有註冊的合格接收者(Receiver) 的IntentFilter進行匹配,若匹配成功則執行相應接收者的onReceive函數,匹配規則見Intent和IntentFilter的匹配規則。
關於registerReceiver動態註冊和通過<receiver>標籤靜態註冊廣播的區別如下:
a.對bindService的調用,<receiver>註冊的廣播,在onReceive結束後廣播即不存在,所以不能在其中給自己非同步傳遞結果,如bindService而只能使用startService,如果想跟service互動可使用peekService。
b. 手動控制。registerReceiver為動態註冊,自己可以手動註冊或是取消註冊;<receiver>標籤為靜態註冊,由系統開機時自動掃描註冊,所以無法手動控制,開機一直運行中。
c. 資源消耗不同。registerReceiver可以手動控制,所以適當的註冊和取消註冊能節省系統資源,<receiver>標籤系統開機後一直有效。
d. 有效期間不同。通過registerReceiver註冊的BroadcastReceiver在對其進行註冊的Context對象"銷毀"了或者調用了unregisterReceiver方法時也就失效了,而通過<receiver>標籤註冊的BroadcastReceiver只要應用程式沒有被刪除就一直有效。
e. 對registerReceiver函數的調用許可不同。通過registerReceiver註冊的BroadcastReceiver在其onReceive函數中可以再次調用某個Context的registerReceiver函數,而通過<receiver>標籤註冊的BroadcastReceiver不允許再調用某個Context的registerReceiver函數 。
f. 使用方式不同。對於自己發送和接受的廣播可以通過registerReceiver註冊,對於系統常用廣播的接收通常用<receiver>標籤註冊。
2、使用舉例
BroadcastReceiverDemo
R.layout.broadcast_receiver_demo的內容為一個簡單的id為sendBroadcast的Button
從上面代碼可以看到我們
a. 建立BroadcastReceiver只需要繼承BroadcastReceiver並重寫OnReceiver函數,加上自己的處理邏輯。
b. 通過registerReceiver註冊廣播,通過unregisterReceiver取消註冊廣播,通過sendBroadcast發送廣播。
其中註冊和取消註冊廣播放在了OnResume和OnPause函數中可以有效節省系統消耗。如果希望廣播一直運行中可以在Activity的OnCreate函數中註冊,在OnDestrory函數中取消註冊。
這裡的MyBroadcastReceiver也可以在AndroidManifest.xml檔案中靜態註冊,這樣程式安裝後便一直運行中。比如希望接收到簡訊到來時的廣播,如下:
<receiver android:name="MyBroadcastReceiver"> <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter></receiver>
3、生命週期
BroadcastReceiver在onReceive函數執行結束後即表示生命週期結束,所以不適合在onReceive中做綁定服務作業,結束後若某個進程只含有該BroadcastReceiver,則優先順序將降低可能被系統回收,所以BroadcastReceiver中不適合做一些非同步作業,如建立線程下載資料,BroadcastReceiver結束後可能在非同步作業完成前進程已經被系統kill。
同時由於ANR限制BroadcastReceiver的onReceive函數必須在10秒內完成,而且onReceive預設會在主線程中執行,所以BroadcastReceiver中不適合做一些耗時操作,對於耗時操作需要交給service處理,比如網路或資料庫耗時操作、對話方塊的顯示(因為現即時間可能逾時,用Notification代替)。
4、安全性
BroadcastReceiver的設計初衷就是從全域考慮的,可以方便應用程式和系統、應用程式之間、應用程式內的通訊,所以對單個應用程式而言BroadcastReceiver是存在安全性問題的,相應問題及解決如下:
a、當應用程式發送某個廣播時系統會將發送的Intent與系統中所有註冊的BroadcastReceiver的IntentFilter進行匹配,若匹配成功則執行相應的onReceive函數。可以通過類似sendBroadcast(Intent, String)的介面在發送廣播時指定接收者必須具備的permission。或通過Intent.setPackage設定廣播僅對某個程式有效。
b. 當應用程式註冊了某個廣播時,即便設定了IntentFilter還是會接收到來自其他應用程式的廣播進行匹配判斷。對於動態註冊的廣播可以通過類似registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)的介面指定寄件者必須具備的permission,對於靜態註冊的廣播可以通過android:exported="false"屬性表示接收者對外部應用程式不可用,即不接受來自外部的廣播。
c.上面兩個問題其實都可以通過LocalBroadcastManager來解決,LocalBroadcastManager只會將廣播限定在當前應用程式中,具體見下面6特殊的BroadcastReceiver中的介紹
d.使用android:protectionLevel
5、分類
BroadcastReceiver可以分為普通和有序兩種,下面6特殊BroadcastReceiver中介紹了其他一些種類。
通過Context.sendBroadcast發送的廣播即為普通廣播,對於普通廣播接收者接收到它的順序是不定的,所以接收者接收到後無法使用其他接收者對它的處理結果也無法停止它。
通過Context.sendOrderedBroadcast發送的廣播即為有序廣播,與普通廣播的不同在於,接收者是有序接收到廣播的並且可以對廣播進行修改或是取消廣播向下傳遞。系統根據接收者定義的優先順序順序決定哪個接收者先接收到它,接收者處理完後可以將結果傳遞給優先順序低的接收者也可以停止廣播使得其他優先順序低的接收者無法接收到該廣播。優先順序通過android:priority屬性定義,數值越大優先順序別越高,取值範圍:-1000到1000,雖然API文檔介紹對sendBroadcast發送的廣播無效,不過本人測試同樣有效,相同優先順序的接收者接收到廣播的順序隨機。Android系統收到簡訊、接到電話後發送的廣播都是有序廣播,所以可以進行簡訊或電話的攔截,即取消廣播。
PS:有序廣播可以在onReceive函數中通過BroadcastReceiver的abortBroadcast介面(這個介面對sendBroadcast發送廣播無效)取消廣播,通過介面sendOrderedBroadcast(Intent,
String, BroadcastReceiver, android.os.Handler, int, String, Bundle)發送的廣播即便優先順序高的廣播取消了廣播,介面參數中指定的BroadcastReceiver依然可以在其他接收者處理完後接收到廣播。通過BroadcastReceiver的getResultExtras介面獲得結果的Bundle再通過Bundle的putString和getString方法修改或擷取資料,可以見本文最後的執行個體代碼舉例。
6、特殊的BroadcastReceiver
a. LocalBroadcastManager本地廣播
android引入了LocalBroadcastManager解決在第4部分安全性介紹的一些問題,LocalBroadcastManager除了能解決BroadcastReceiver進程間安全性問題外,相對Context操作的BroadcastReceiver而言還具有更高的運行效率。
使用LocalBroadcastManager需要引入Android Support Library,如何引入見Add Support Package。
本地廣播通過LocalBroadcastManager.getInstance(context).sendBroadcast(intent)發送廣播,LocalBroadcastManager.getInstance(context).registerReceiver註冊服務,通過LocalBroadcastManager.getInstance(context).unregisterReceiver取消註冊服務,其他同普通廣播.
b. Sticky Broadcast粘性廣播
如果寄件者發送了某個廣播,而接收者在這個廣播發送後才註冊自己的Receiver,這時接收者便無法接收到剛才的廣播,為此Android引入了StickyBroadcast,在廣播發送結束後會儲存剛剛發送的廣播(Intent),這樣當接收者註冊完Receiver後就可以繼續使用剛才的廣播。如果在接收者註冊完成前發送了多條相同Action的粘性廣播,註冊完成後只會收到一條該Action的廣播,並且訊息內容是最後一次廣播內容。系統網路狀態的改變發送的廣播就是粘性廣播。
粘性廣播通過Context的sendStickyBroadcast(Intent)介面發送,需要添加許可權<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
也可以通過Context的removeStickyBroadcast(Intent intent)介面移除緩衝的粘性廣播。
c. OrderedBroadcastReceiver有序廣播
這個在5分類中已經介紹,接收者有序接收廣播並可以修改廣播結果或是取消廣播,通過Context的sendOrderedBroadcast介面發送
d. StickyOrderedBroadcast粘性有序廣播
這個就是粘性廣播和有序廣播的結合了,通過Context的sendStickyOrderedBroadcast介面發送。
各種廣播操作Demo範例程式碼見BroadcastReceiverDemo@GoogleCode,由於本地廣播的support library暫時下載不了,不包括本地廣播,本地廣播操作間上面介紹。
注意AndroidManifest檔案中需要添加粘性廣播操作許可權<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
參考:
http://developer.android.com/reference/android/content/BroadcastReceiver.html
轉自:http://www.cnblogs.com/trinea/archive/2012/11/09/2763182.html