Android有四大組件,分別為:Activity(活動)、Service(服務)、Content Provider(內容提供器)、Broadcast Receiver(廣播接收者)。
引入廣播的目的是便于接收和發送系統級(而不只是應用內部)的通知,使得Android的任意一個應用可以接收來自于系統和其他應用的消息。其機制類似于設計模式中的觀察者模式(或發布-訂閱模式)。
廣播的Android官方文檔:Broadcasts
全局廣播
因為下面還會介紹一種本地廣播,因此將這部分稱為全局廣播。“全局”體現在所有應用都可以接收到廣播,只要這些應用有注冊接收者。
兩種廣播類型
標準廣播
標準廣播是我們通常意義上所理解的廣播,即一旦發送廣播,在廣播范圍內的接收者都能同時收到廣播。
有序廣播
“有序”指的是接收者排隊按順序接收廣播,就像傳紙條游戲一樣。這種類型非常重要的一點是先接收廣播的接收者可以決定是否將廣播繼續傳遞下去。
廣播的發送者
Android系統
系統廣播包括但不限于:網絡狀態(7.0系統不推薦使用廣播來接收)、開關機狀態、電量狀態。
某個應用
通常是自定義的廣播
廣播接收者
廣播接收者必須繼承BroadcastReceiver這個類。BroadcastReceiver是一個抽象類,它做了很多實現,但留下一個抽象方法給程序員去實現。
public abstract void onReceive(Context context, Intent intent);
繼承BroadcastReceiver之后只需實現這個方法。在里面寫上接收到所期望的廣播時的處理代碼就行了。需要注意的是,不能在這里面做耗時的處理。一旦超過10秒還沒return,程序就會報錯。如果想做耗時處理,可以開啟后臺服務。
在onReceive里開啟線程之前需要執行goAsync()獲取PendingResult,以此告訴系統當onReceive()執行結束之后,需要一些時間來完成線程的任務。在線程里面需要調用PendingResult的finish()來告訴系統線程已經完成任務。
兩種廣播接收者注冊方式
在廣播接收者的代碼中沒有聲明響應哪些廣播,因此需要在其他地方注冊。
代碼中基于Context的動態注冊
由于Context有Activity級和Application級的,因此這兩種方式的廣播有效時期不一樣。Activity級的廣播接收者會在Activity的onDestroy()執行之后變為無效,而Application級的廣播接收者只要APP還在運行,它就有效。
當使用Context的廣播接收者時,需要調用registerReceiver(BroadcastReceiver, IntentFilter) 和 unregisterReceiver(BroadcastReceiver)來注冊和注銷。這兩個方法都在Context類里面。如果想注冊Application級別的,就需要getApplicationContext()。在注冊時傳入IntentFilter用于指定期望接收的廣播。
AndroidManifest.xml的靜態注冊
Android系統的包管理器(package manager)會在APP安裝到手機的時候注冊寫在這里的廣播接收者。一旦注冊,這個廣播接收者成為指向該APP的一個獨立個體。這樣就意味著即使APP沒有在運行,這個廣播仍然可以正常運作。
廣播接收者需要寫在application標簽內,它的標簽是receiver,需要指定name和intent-filter。舉個例子:
<application ...> ... <receiver android:name=".MyBroadcastReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver> </application>
選擇哪種注冊方式主要看需求。如果想要在程序沒有啟動的情況下就響應廣播,那么就采用靜態注冊;如果只想在程序啟動的情況下接收廣播,就用動態注冊。
無論是用哪種方式注冊廣播,其廣播接收器的寫法都是一樣的。
自定義廣播
自定義廣播的關鍵是Action的定義。
Intent intent = new Intent("com.example.yourappname.YOUR_BROADCAST_NAME");
sendBroadcast(intent);
需要注意的是,自定義的Intent Action是一個字符串,這個字符串你可以按照以上的格式寫。
在寫接收者的Action時,把上面定義的字符串作為Action復制過去就行了。
發送有序廣播
將sendBroadcast(intent);
改為 sendOrderedBroadcast(intent, null)
就行了。第二個參數是權限相關的字符串,如果沒有權限要求,就填null。
如何決定廣播的順序?
intent filter有一個priority的參數,設置得越高就越先接收。
如何截斷廣播?
在BroadcastReceiver的onReceive中調用abortBroadcast()就行了。如果你想在某種情況下截斷廣播,則需要判斷語句。
前面的接收者和后面的接收者之間溝通
通過在onReceive()中執行setResultData()來設置給后面接收者的內容,執行getResultData()來獲取前面接收者設置的內容。
本地廣播
某些廣播的目的地是應用內部,它們可能含有關鍵性的數據。為了防止這些廣播被其他程序獲取,引入了LocalBroadcastManager(本地廣播)。
本地廣播和全局廣播的不同之處主要有以下幾點:
- 不能在AndroidManifest.xml里注冊receiver
- 需要獲取LocalBroadcastManager實例
- 發送廣播時要用LocalBroadcastManager實例調用sendBroadcast(Intent intent)
廣播接收者的寫法是一樣的。
文章列表