編輯:關於android開發
前些天把四大組件之一的Service扯了一遍,今天就要開始談談它的弟兄BroadcastReceiver了。寫到這裡我挺糾結的,因為廣播接收者確實比較簡單,但是各位就不要以為簡單的就不內涵,也許我們慢慢探討一下還能有另外一片天地。
慣例還是先會介紹一下基礎的知識,後面會說說關於BroadcastReceiver的接收順序還有其他的一些小知識。
BroadcastReceiver的概念
BroadcastReceiver的作用主要是用來監聽系統或者應用發出的廣播信息,然後根據廣播信息作為相應的邏輯處理;說通俗點其實上就是一種全局監聽器,要來實現系統中不同組件之間的通信。有時候也會用來作為傳輸少量而且發送頻率低的數據,但是如果數據的發送頻率比較高或者數量比較大就不建議用廣播接收者來接收了,因為這樣的效率很不好,因為BroadcastReceiver接收數據的開銷還是比較大的。
BroadcastReceiver的基礎使用
我們先來看看廣播接收者的代碼,如下:
1 public class MyBroadcastReceiver extends BroadcastReceiver { 2 @Override 3 public void onReceive(Context arg0, Intent arg1) { 4 // 用來實現廣播接受者接收到廣播後執行的代碼邏輯 5 } 6 }
簡單而完美,實現一個廣播接受者僅僅需要我們重寫一個函數onReceiver(),如果廣播接受者接收到廣播後將會執行該函數;但是這個前提是需要將這個廣播接收者進行注冊,一般來說,BroadcastReceiver的注冊方式有且只有兩種,一種是靜態注冊,另外一種是動態注冊,廣播接收者在注冊後就開始監聽系統或者應用之間發送的廣播消息。
靜態注冊的方式:打開AndroidManifest清單文件中,像Activity、Service那種添加一個數據項進行注冊,如下:
<receiver android:name=".MyBroadcastReceiver"> <intent-filter> <!-- action的命名規則一般建議為:包名.intent.類名 --> <action android:name="com.net168.testBcr.intent.mybroadcastreceiver"/> </intent-filter> </receiver>
靜態注冊的廣播接收者就是一個常駐在系統中的全局監聽器,也就是說如果你應用中配置了一個靜態的BroadcastReceiver,而且你安裝了應用而無論應用是否處於運行狀態,廣播接收者都是已經常駐在系統中了。但是有些人會很郁悶怎麼銷毀掉這個廣播接收者,其實只要調用PackageManager將Receiver禁用就行了,簡單實用吧?
動態注冊的方式:使用registerReceiver(receiver, filter)進行廣播接收者的注冊,代碼如下:
//filter是設置receiver的攔截器 IntentFilter filter = new IntentFilter("com.net168.testBcr.intent.mybroadcastreceiver"); MyBroadcastReceiver receiver = new MyBroadcastReceiver(); //動態注冊廣播接收者 registerReceiver(receiver, filter);
動態注冊的廣播接收者只有執行了registerReceiver(receiver, filter)才會開始監聽廣播消息,並對廣播消息作為相應的處理。
銷毀一個動態注冊的BroadcastReceiver如下:
//撤銷廣播接受者的動態注冊 unregisterReceiver(receiver);
撤銷注冊後廣播接收者將不會再監聽系統的廣播消息。
靜態注冊的BroadcastReceiver和動態注冊的BroadcastReceiver的一些區別
1、靜態注冊的廣播接收者一經安裝就常駐在系統之中,不需要重新啟動喚醒接收者;動態注冊的廣播接收者隨著應用的生命周期,由registerReceiver開始監聽,由unregisterReceiver撤銷監聽,另外需要注意的一點就是如果應用退出後,沒有撤銷已經注冊的接收者應用應用將會報錯。
2、當廣播接收者通過intent啟動一個activity或者service時,如果intent中無法匹配到相應的組件。動態注冊的廣播接收者將會導致應用報錯,而靜態注冊的廣播接收者將不會有任何報錯,因為自從應用安裝完成後,廣播接收者跟應用已經脫離了關系。
廣播接收者機制
當系統或應用發出廣播時,將會掃描系統中的所有廣播接收者,通過action匹配將廣播發送給相應的接收者,接收者收到廣播後將會產生一個廣播接收者的實例,執行其中的onReceiver()這個方法;特別需要注意的是這個實例的生命周期只有10秒,如果10秒內沒執行結束onReceiver(),系統將會報錯。另外在onReceiver()執行完畢之後,該實例將會被銷毀,所以不要在onReceiver()中執行耗時操作,也不會在裡面創建子線程處理業務(因為可能子線程沒處理完,接收者就被回收了);正確的處理方法就是通過intent調用activity或者service處理業務。
發送廣播
廣播有三種類型:普通廣播和有序廣播,還有另外一種不怎麼常用的粘性廣播。
Android為了滿足各種應用要求,設置了兩個發送廣播的方式,各有特點。一般普通廣播可以應用在需要通知各個廣播接收者的情況下如開機啟動結束發送的廣播;而有序廣播則應用在需要有特定攔截的場景下如黑名單短信、電話攔截。
普通廣播:普通廣播是完全異步的,可以在同一時刻(邏輯上)被所有接收者接收到,消息傳遞的效率比較高,並且無法中斷廣播的傳播。
Intent intent = new Intent(); intent.setAction("com.net168.testBcr.intent.mybroadcastreceiver"); intent.putExtra("data", "hello"); //發送普通廣播 sendBroadcast(intent);
通過sendBroad(intent)來發送普通的廣播消息。
有序廣播:發送有序廣播後,廣播接收者將按預先聲明的優先級依次接收Broadcast。優先級高的優先接收到廣播,而在其onReceiver()執行過程中,廣播不會傳播到下一個接收者,此時當前的廣播接收者可以終止廣播繼續向下傳播,也可以將intent中的數據進行修改設置,然後將其傳播到下一個廣播接收者。
通過sendOrderedBroadcast()來發送有序廣播。
//發送有序廣播 sendOrderedBroadcast(intent, null);
對於有序廣播接收者,我們可以再onReceiver中進行一些操作
public void onReceive(Context arg0, Intent intent) { //獲取上一個廣播的bundle數據 Bundle bundle = getResultExtras(true);//true:前一個廣播沒有結果時創建新的Bundle;false:不創建Bundle bundle.putString("key", "168168"); //將bundle數據放入廣播中傳給下一個廣播接收者 setResultExtras(bundle); //終止廣播傳給下一個廣播接收者 abortBroadcast(); }
在有序廣播中,我們可以在前一個廣播接收者將處理好的數據傳送給後面的廣播接收者,也可以調用abortBroadcast()來終結廣播的傳播。
粘性廣播:該廣播比較不常用,我們可以通過sendStickyBroadcast()來發送該類型的廣播信息,這種的廣播的最大特點是,當粘性廣播發送後,最後的一個粘性廣播會滯留在操作系統中。如果在粘性廣播發送後的一段時間裡,如果有新的符合廣播的動態注冊的廣播接收者注冊,將會收到這個廣播消息,雖然這個廣播是在廣播接收者注冊之前發送的,另外一點,對於靜態注冊的廣播接收者來說,這個等同於普通廣播。
廣播接收者接收廣播的次序
注意一點:廣播接收者的優先級范圍谷歌文檔上標示的最大級為1000,但是實際上最大的級數是Integer.MAX(即2147483647)。
靜態廣播接收的處理器是由PackageManagerService負責,當手機啟動或者新安裝了應用的時候,PackageManagerService會掃描手機中所有已安裝的APP應用,將AndroidManifest.xml中有關注冊廣播的信息解析出來,存儲至一個全局靜態變量當中。需要注意的是:
1、PackageManagerService掃描目錄的順序如下:
system/framework -> system/app -> vendor/app -> data/app -> drm/app-private
2、當處於同一目錄下時:按照file.list()的返回順序。(題外話:因為在data/app下的應用都是用戶安裝的,並且都是以com.xxx.xxx-1.apk 的形式出現,所以如果打算做手機管家之類的應用,需要好好的研究下包名,爭取在file.list()的獨木橋下搶的頭籌---優先接收開機啟動完成的廣播。)
動態廣播接收的處理器是由ActivityManagerService負責,當APP的服務或者進程起來之後,執行了注冊廣播接收的代碼邏輯,即進行加載,最後會存儲在一個另外的全局靜態變量中。需要注意的是:
1、 這個並非是一成不變的,當程序被殺死之後,已注冊的動態廣播接收器也會被移出全局變量,直到下次程序啟動,再進行動態廣播的注冊,當然這裡面的順序也已經變更了一次。
2、這裡也並沒完整的進行廣播的排序,只記錄的注冊的先後順序,並未有結合優先級的處理。
廣播發出的時候,廣播接收者接收的順序如下:
如果廣播為有序廣播,那麼會將動態廣播處理器和靜態廣播處理器合並在一起處理廣播的消息,最終確定廣播接收的順序:
1、優先級高的先接收 2、同優先級的動靜態廣播接收器,動態優先於靜態 3、同優先級的動態廣播接收器或者同優先級的靜態廣播接收器;分靜態:先掃描的大於後掃描的,動態:先注冊的大於後注冊的。 當廣播為普通廣播時,有如下的接收順序: 1、無視優先級,動態廣播接收器優先於靜態廣播接收器 2、同優先級的動態廣播接收器或者同優先級的靜態廣播接收器;分靜態:先掃描的大於後掃描的,動態:先注冊的大於後注冊的。 作者:enjoy風鈴App解讀,新聞解讀app一直不懂別人口中說的原生開發、混合式開發。今天突然看了一篇文章講解的是什麼叫做原生App?移動 Web App?混合APP?分享給大家。 原生A
android ListView_顯示數據庫數據,androidlistviewxml <?xml version=1.0?> -<LinearLay
Android上在兩個Activity之間傳遞Bitmap對象 Android上在兩個Activity之間傳遞Bitmap對象 因為我做Android應用的時間不長,
Android中訪問sdcard路徑的幾種方式,androidsdcard以前的Android(4.1之前的版本)中,SDcard路徑通過“/sdcard”或者“/mnt