BroadcastReceiver基礎使用
BroadCastReceiver簡介
BroadCastReceiver,即廣播接收器,運行在主線程用於監聽全局廣播
作爲Android四大組件之一,BroadCastReceiver起着重要的作用,一般用於接收推送,跨進程通信等不方便直接通信操作的地方或者監聽某些不定時完成的事務
廣播主要有兩種:有序廣播和無序廣播
- 無序廣播:所有跟廣播的intent匹配的廣播接收者都可以收到該廣播,並且是沒有先後順序,效率搞,但是接收者不能傳遞也不能截斷廣播
- 有序廣播:所有跟廣播的intent匹配的廣播接收者都可以收到該廣播,但是會按照廣播接收者的優先級來決定接收的先後順序,每一個接收者都有權修改並將修改的廣播傳給下一個接收者,也可以攔截。
BroadcastReceiver的實現原理
之前使用的時候並沒有在意它的實現原理,只是知道這麼用
廣播的設計模式是標準的觀察者模式,對於廣播而言最重要的是Android的AMS(ActivityManagerService),消息發佈者在AMS中註冊,通過Binder機制發送廣播,AMS在註冊列表尋找到合適的接收者,將廣播發送到接收者的消息循環隊列(BroadcastQueue)中,廣播接收者通過消息循環拿到廣播並調用回調方法onReceive();
這觀察者模式好屌,嚇得我趕緊去看這個設計模式怎麼用了
定義一個BroadcastReceiver
定義個廣播接收器還是挺簡單的
- 首先我們要新建一個類(至於是單獨文件的類還是內部類這個要看使用場景,不過都可以的)並繼承BroadcastReceiver類
- 重寫裏面的onReceive方法
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//接收廣播後的操作
}
}
BroadcastReceiver的註冊
作爲Android四大組件之一,你Activity和Service都在Manifest裏面註冊了,我BroadcastReceiver要是不註冊,我不要面子噠?
BroadcastReceiver的註冊分爲兩種:靜態註冊和動態註冊
靜態註冊
靜態註冊實在AndroidManifest裏面添加
<receiver>
標籤
<receiver
//是否能夠實例化這個接收器可以爲true,若爲false則不能被實例化
android:enabled=["true" | "false"]
//此接收器能否接受其他APP發出的廣播,如果內部包含intent-filter標籤則默認爲true,否則默認false
android:exported=["true" | "false"]
//一個代表廣播接收器的圖標,不定義默認爲application標籤的icon
android:icon="drawable resource"
android:label="string resource"//標籤
//這個屬性一般爲廣播接收器實現類的類名(全名,要有包名的那種;或者直接.CLASSNAME,這樣系統會默認吧manifest的包名加到前面)
android:name="string"
//這個屬性用於定義把消息發送給該廣播接收器的廣播器所必須要有的權限。
android:permission="string"
這個屬性用於設置該廣播接收器應該運行在那個進程中的進程名。
android:process="string">
<intent-filter>
//這裏的action,就是我們發送的廣播的事件名
<action android:name="actionName" />
</intent-filter>
</receiver>
當此app首次啓動時,系統會自動實例化該廣播接收器的實現類,並註冊到系統中。
動態註冊
是指不在Manifest裏面添加標籤,而是在代碼中動態調用Context的registerReceiver()方法。
private MyBroadcastReceiver mBroadcastReceiver;
@Override
protected void onResume(){
super.onResume();
mBroadcastReceiver = new MyBroadcastReceiver ();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
registerReceiver(mBroadcastReceiver, intentFilter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mBroadcastReceiver);
}
動態廣播由於需要註銷防止內存泄漏,所以推薦在onResume方法中註冊,onPause方法中註銷,同時重複註冊,重複註銷也不允許
在onResume()註冊、onPause()註銷是因爲onPause()在App死亡前一定會被執行,從而保證廣播在App死亡前一定會被註銷,從而防止內存泄露。
靜態註冊與動態註冊的區別
- 兩個方式的註冊方式不同
- 靜態:在manifest中註冊
- 動態:在代碼中註冊
- 兩個方式的監聽範圍不同
- 靜態:會時刻監聽廣播
- 動態:在特定時刻監聽廣播
- 兩個方式的生命週期不同
- 靜態:常駐後臺,不受任何組件生命週期影響,耗電多佔內存大
- 動態:部常駐,靈活,跟隨組件的生命週期變化,一旦移除就不會接受廣播
發送廣播
廣播是通過sendBroadcast()方法,以Intent爲傳輸工具進行發送的
廣播主要分爲5類:
- 普通廣播
- 系統廣播
- 有序廣播
- 粘性廣播
- 應用內廣播
普通廣播
Intent intent = new Intent();
intent.setAction(NROMAL_ACTION);
sendBroadcast(intent);
NROMAL_ACTION 就是你之前註冊的廣播事件
系統廣播
這個並不是手動發送的,而是系統默認發送的,我們只需要監聽就好
具體操作 | action名稱 |
---|---|
監聽網絡變化 | android.net.conn.CONNECTIVITY_CHANGE |
關閉或打開飛行模式 | Intent.ACTION_AIRPLANE_MODE_CHANGED |
充電時或電量發生變化 | Intent.ACTION_BATTERY_CHANGED |
電池電量低 | Intent.ACTION_BATTERY_LOW |
電池電量充足(即從電量低變化到飽滿時會發出廣播 | Intent.ACTION_BATTERY_OKAY |
系統啓動完成後(僅廣播一次) | Intent.ACTION_BOOT_COMPLETED |
按下照相時的拍照按鍵(硬件按鍵)時 | Intent.ACTION_CAMERA_BUTTON |
屏幕鎖屏 | Intent.ACTION_CLOSE_SYSTEM_DIALOGS |
設備當前設置被改變時(界面語言、設備方向等) | Intent.ACTION_CONFIGURATION_CHANGED |
插入耳機時 | Intent.ACTION_HEADSET_PLUG |
未正確移除SD卡但已取出來時(正確移除方法:設置–SD卡和設備內存–卸載SD卡) | Intent.ACTION_MEDIA_BAD_REMOVAL |
插入外部儲存裝置(如SD卡) | tent.ACTION_MEDIA_CHECKING |
成功安裝APK | Intent.ACTION_PACKAGE_REMOVED |
成功刪除APK | Intent.ACTION_BATTERY_CHANGED |
重啓設備 | Intent.ACTION_REBOOT |
屏幕被關閉 | Intent.ACTION_SCREEN_OFF |
屏幕被打開 | Intent.ACTION_SCREEN_ON |
關閉系統時 | Intent.ACTION_SHUTDOWN |
重啓設備 | Intent.ACTION_REBOOT |
當使用系統廣播時,只需要在註冊廣播接收者時定義相關的action即可,並不需要手動發送廣播,當系統有相關操作時會自動進行系統廣播
有序廣播
發送出去的廣播被廣播接收者按照先後順序接收,這裏的有序是針對接受者的
- 廣播接收的順序規則
- 按照Priority屬性的值,從大到小排序
- Priority屬性的值相同時,動態註冊的廣播優先
使用方式
sendOrderedBroadcast(intent);
應用內廣播
- 註冊廣播時將exported屬性設置爲false,使得非本App內部發出的此廣播不被接收;
- 發送廣播時指定該廣播接收器所在的包名,此廣播將只會發送到此包中的App內與之相匹配的有效廣播接收器中,通過intent.setPackage(packageName)指定報名
在廣播發送和接收時,增設相應權限permission,用於權限驗證;
除了以上幾種方式,也可以使用LocalBroadcastManager
使用方式上與全局廣播幾乎相同,只是註冊/取消註冊廣播接收器和發送廣播時將參數的context變成了LocalBroadcastManager的單一實例,對於LocalBroadcastManager方式發送的應用內廣播,只能通過LocalBroadcastManager動態註冊,不能靜態註冊
//註冊應用內廣播接收器
//步驟1:實例化BroadcastReceiver子類 & IntentFilter
MyBroadcastReceiver mBroadcastReceiver = new MyBroadcastReceiver ();
IntentFilter intentFilter = new IntentFilter();
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//步驟3:設置接收廣播的類型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
//步驟4:調用LocalBroadcastManager單一實例的registerReceiver()方法進行動態註冊
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
//取消註冊應用內廣播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
//發送應用內廣播
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);
關於onReceive(Context context,Intent intent)方法
對於不同註冊方式的廣播接收器回調OnReceive(Context context,Intent intent)中的context返回值是不一樣的
- 對於靜態註冊(全局+應用內廣播),回調onReceive(context, intent)中的context返回值是:ReceiverRestrictedContext;
- 對於全局廣播的動態註冊,回調onReceive(context, intent)中的context返回值是:Activity Context;
- 對於應用內廣播的動態註冊(LocalBroadcastManager方式),回調onReceive(context, intent)中的context返回值是:Application Context。
- 對於應用內廣播的動態註冊(非LocalBroadcastManager方式),回調onReceive(context, intent)中的context返回值是:Activity Context;