一、 定義
-
BroadcastReceiver(廣播接收器),屬于Android四大組件之一 - 在Android開(kāi)發(fā)中,BroadcastReceiver的應(yīng)用場(chǎng)景非常多廣播,是一個(gè)全局的監(jiān)聽(tīng)器,屬于
Android四大組件之一
Android廣播分為兩個(gè)角色:廣播發(fā)送者、廣播接收者
二、 作用
用于監(jiān)聽(tīng) / 接收 應(yīng)用發(fā)出的廣播消息,并做出響應(yīng)
-
應(yīng)用場(chǎng)景
a. 不同組件之間通信(包括應(yīng)用內(nèi) / 不同應(yīng)用之間)b. 與
Android系統(tǒng)在特定情況下的通信如當(dāng)電話呼入時(shí)、網(wǎng)絡(luò)可用時(shí)
c. 多線程通信
三、實(shí)現(xiàn)原理
-
Android中的廣播使用了設(shè)計(jì)模式中的觀察者模式:基于消息的發(fā)布/訂閱事件模型。因此,Android將廣播的發(fā)送者 和 接收者 解耦,使得系統(tǒng)方便集成,更易擴(kuò)展
-
模型中有3個(gè)角色:
- 消息訂閱者(廣播接收者)
- 消息發(fā)布者(廣播發(fā)布者)
- 消息中心(
AMS,即Activity Manager Service)

-
原理描述:
廣播接收者 通過(guò)
Binder機(jī)制在AMS注冊(cè)廣播發(fā)送者 通過(guò)
Binder機(jī)制向AMS發(fā)送廣播-
AMS根據(jù) 廣播發(fā)送者 要求,在已注冊(cè)列表中,尋找合適的廣播接收者尋找依據(jù):
IntentFilter / Permission AMS將廣播發(fā)送到合適的廣播接收者相應(yīng)的消息循環(huán)隊(duì)列中;廣播接收者通過(guò) 消息循環(huán) 拿到此廣播,并回調(diào)
onReceive()
特別注意:廣播發(fā)送者 和 廣播接收者的執(zhí)行 是 異步的,發(fā)出去的廣播不會(huì)關(guān)心有無(wú)接收者接收,也不確定接收者到底是何時(shí)才能接收到;
四、具體使用
具體使用流程如下:

接下來(lái)我將一步步介紹如何使用
即上圖中的 開(kāi)發(fā)者手動(dòng)完成部分
4.1 自定義廣播接收者BroadcastReceiver
繼承自BroadcastReceivre基類
-
必須復(fù)寫(xiě)抽象方法onReceive()方法
- 廣播接收器接收到相應(yīng)廣播后,會(huì)自動(dòng)回調(diào)onReceive()方法
- 一般情況下,onReceive方法會(huì)涉及與其他組件之間的交互,如發(fā)送Notification、啟動(dòng)service等
- 默認(rèn)情況下,廣播接收器運(yùn)行在UI線程,因此,onReceive方法不能執(zhí)行耗時(shí)操作,否則將導(dǎo)致ANR。
代碼范例
mBroadcastReceiver.java
public class mBroadcastReceiver extends BroadcastReceiver {
//接收到廣播后自動(dòng)調(diào)用該方法
@Override
public void onReceive(Context context, Intent intent) {
//寫(xiě)入接收廣播后的操作
}
}
4.2 廣播接收器注冊(cè)
注冊(cè)的方式分為兩種:靜態(tài)注冊(cè)、動(dòng)態(tài)注冊(cè)
4.2.1 靜態(tài)注冊(cè)
- 在AndroidManifest.xml里通過(guò) <receive> 標(biāo)簽聲明
- 屬性說(shuō)明:
<receiver
android:enabled=["true" | "false"]
//此broadcastReceiver能否接收其他App的發(fā)出的廣播
//默認(rèn)值是由receiver中有無(wú)intent-filter決定的:如果有intent-filter,默認(rèn)值為true,否則為false
android:exported=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
//繼承BroadcastReceiver子類的類名
android:name=".mBroadcastReceiver"
//具有相應(yīng)權(quán)限的廣播發(fā)送者發(fā)送的廣播才能被此BroadcastReceiver所接收;
android:permission="string"
//BroadcastReceiver運(yùn)行所處的進(jìn)程
//默認(rèn)為app的進(jìn)程,可以指定獨(dú)立的進(jìn)程
//注:Android四大基本組件都可以通過(guò)此屬性指定自己的獨(dú)立進(jìn)程
android:process="string" >
//用于指定此廣播接收器將接收的廣播類型
//本示例中給出的是用于接收網(wǎng)絡(luò)狀態(tài)改變時(shí)發(fā)出的廣播
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
-
注冊(cè)示例
<receiver //此廣播接收者類是mBroadcastReceiver android:name=".mBroadcastReceiver" > //用于接收網(wǎng)絡(luò)狀態(tài)改變時(shí)發(fā)出的廣播 <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> </intent-filter> </receiver>當(dāng)此App首次啟動(dòng)時(shí),系統(tǒng)會(huì)自動(dòng)實(shí)例化mBroadcastReceiver類,并注冊(cè)到系統(tǒng)中。
4.2.2 動(dòng)態(tài)注冊(cè)
在代碼中通過(guò)調(diào)用Context的registerReceiver()方法進(jìn)行動(dòng)態(tài)注冊(cè)BroadcastReceiver,具體代碼如下:
@Override
protected void onResume() {
super.onResume();
//實(shí)例化BroadcastReceiver子類 & IntentFilter
mBroadcastReceiver mBroadcastReceiver = new mBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
//設(shè)置接收廣播的類型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
//調(diào)用Context的registerReceiver()方法進(jìn)行動(dòng)態(tài)注冊(cè)
registerReceiver(mBroadcastReceiver, intentFilter);
}
//注冊(cè)廣播后,要在相應(yīng)位置記得銷毀廣播
//即在onPause() 中unregisterReceiver(mBroadcastReceiver)
//當(dāng)此Activity實(shí)例化時(shí),會(huì)動(dòng)態(tài)將MyBroadcastReceiver注冊(cè)到系統(tǒng)中
//當(dāng)此Activity銷毀時(shí),動(dòng)態(tài)注冊(cè)的MyBroadcastReceiver將不再接收到相應(yīng)的廣播。
@Override
protected void onPause() {
super.onPause();
//銷毀在onResume()方法中的廣播
unregisterReceiver(mBroadcastReceiver);
}
特別注意
動(dòng)態(tài)廣播最好在Activity的onResume()注冊(cè)、onPause()注銷。
-
原因:
對(duì)于動(dòng)態(tài)廣播,有注冊(cè)就必然得有注銷,否則會(huì)導(dǎo)致內(nèi)存泄露
重復(fù)注冊(cè)、重復(fù)注銷也不允許
4.2.3 兩種注冊(cè)方式的區(qū)別

4.3 廣播發(fā)送者向AMS發(fā)送廣播
4.3.1 廣播的發(fā)送
- 廣播是用”意圖(Intent)“標(biāo)識(shí)
- 定義廣播的本質(zhì):定義廣播所具備的“意圖(Intent)”
- 廣播發(fā)送:廣播發(fā)送者將此廣播的”意圖“通過(guò)sendBroadcast()方法發(fā)送出去
4.3.2 廣播的類型
廣播的類型主要分為5類:
- 普通廣播(Normal Broadcast)
- 系統(tǒng)廣播(System Broadcast)
- 有序廣播(Ordered Broadcast)
- 粘性廣播(Sticky Broadcast)
- App應(yīng)用內(nèi)廣播(Local Broadcast)
具體說(shuō)明如下:
①. 普通廣播(Normal Broadcast)
即開(kāi)發(fā)者自身定義intent的廣播(最常用)。發(fā)送廣播使用如下:
Intent intent = new Intent();
//對(duì)應(yīng)BroadcastReceiver中intentFilter的action
intent.setAction(BROADCAST_ACTION);
//發(fā)送廣播
sendBroadcast(intent);
- 若被注冊(cè)了的廣播接收者中注冊(cè)時(shí)intentFilter的action與上述匹配,則會(huì)接收此廣播(即進(jìn)行回調(diào)onReceive())。如下mBroadcastReceiver則會(huì)接收上述廣播
<receiver
//此廣播接收者類是mBroadcastReceiver
android:name=".mBroadcastReceiver" >
//用于接收網(wǎng)絡(luò)狀態(tài)改變時(shí)發(fā)出的廣播
<intent-filter>
<action android:name="BROADCAST_ACTION" />
</intent-filter>
</receiver>
- 若發(fā)送廣播有相應(yīng)權(quán)限,那么廣播接收者也需要相應(yīng)權(quán)限
②. 系統(tǒng)廣播(System Broadcast)
- Android中內(nèi)置了多個(gè)系統(tǒng)廣播:只要涉及到手機(jī)的基本操作(如開(kāi)機(jī)、網(wǎng)絡(luò)狀態(tài)變化、拍照等等),都會(huì)發(fā)出相應(yīng)的廣播
- 每個(gè)廣播都有特定的Intent - Filter(包括具體的action),Android系統(tǒng)廣播action如下:
| 系統(tǒng)操作 | action |
|---|---|
| 監(jiān)聽(tīng)網(wǎng)絡(luò)變化 | android.net.conn.CONNECTIVITY_CHANGE |
| 關(guān)閉或打開(kāi)飛行模式 | Intent.ACTION_AIRPLANE_MODE_CHANGED |
| 充電時(shí)或電量發(fā)生變化 | Intent.ACTION_BATTERY_CHANGED |
| 電池電量低 | Intent.ACTION_BATTERY_LOW |
| 電池電量充足(即從電量低變化到飽滿時(shí)會(huì)發(fā)出廣播 | Intent.ACTION_BATTERY_OKAY |
| 系統(tǒng)啟動(dòng)完成后(僅廣播一次) | Intent.ACTION_BOOT_COMPLETED |
| 按下照相時(shí)的拍照按鍵(硬件按鍵)時(shí) | Intent.ACTION_CAMERA_BUTTON |
| 屏幕鎖屏 | Intent.ACTION_CLOSE_SYSTEM_DIALOGS |
| 設(shè)備當(dāng)前設(shè)置被改變時(shí)(界面語(yǔ)言、設(shè)備方向等) | Intent.ACTION_CONFIGURATION_CHANGED |
| 插入耳機(jī)時(shí) | Intent.ACTION_HEADSET_PLUG |
| 未正確移除SD卡但已取出來(lái)時(shí)(正確移除方法:設(shè)置--SD卡和設(shè)備內(nèi)存--卸載SD卡) | Intent.ACTION_MEDIA_BAD_REMOVAL |
| 插入外部?jī)?chǔ)存裝置(如SD卡) | Intent.ACTION_MEDIA_CHECKING |
| 成功安裝APK | Intent.ACTION_PACKAGE_ADDED |
| 成功刪除APK | Intent.ACTION_PACKAGE_REMOVED |
| 重啟設(shè)備 | Intent.ACTION_REBOOT |
| 屏幕被關(guān)閉 | Intent.ACTION_SCREEN_OFF |
| 屏幕被打開(kāi) | Intent.ACTION_SCREEN_ON |
| 關(guān)閉系統(tǒng)時(shí) | Intent.ACTION_SHUTDOWN |
| 重啟設(shè)備 | Intent.ACTION_REBOOT |
注:當(dāng)使用系統(tǒng)廣播時(shí),只需要在注冊(cè)廣播接收者時(shí)定義相關(guān)的action即可,并不需要手動(dòng)發(fā)送廣播,當(dāng)系統(tǒng)有相關(guān)操作時(shí)會(huì)自動(dòng)進(jìn)行系統(tǒng)廣播
③. 有序廣播(Ordered Broadcast)
-
定義
發(fā)送出去的廣播被廣播接收者按照先后順序接收有序是針對(duì)廣播接收者而言的
-
廣播接受者接收廣播的順序規(guī)則(同時(shí)面向靜態(tài)和動(dòng)態(tài)注冊(cè)的廣播接受者)
- 按照Priority屬性值從大-小排序;
- Priority屬性相同者,動(dòng)態(tài)注冊(cè)的廣播優(yōu)先;
-
特點(diǎn)
- 接收廣播按順序接收
- 先接收的廣播接收者可以對(duì)廣播進(jìn)行截?cái)啵春蠼邮盏膹V播接收者不再接收到此廣播;
- 先接收的廣播接收者可以對(duì)廣播進(jìn)行修改,那么后接收的廣播接收者將接收到被修改后的廣播
-
具體使用
有序廣播的使用過(guò)程與普通廣播非常類似,差異僅在于廣播的發(fā)送方式:sendOrderedBroadcast(intent);
④. App應(yīng)用內(nèi)廣播(Local Broadcast)
背景
Android中的廣播可以跨App直接通信(exported對(duì)于有intent-filter情況下默認(rèn)值為true)-
沖突
可能出現(xiàn)的問(wèn)題:- 其他App針對(duì)性發(fā)出與當(dāng)前App intent-filter相匹配的廣播,由此導(dǎo)致當(dāng)前App不斷接收廣播并處理;
- 其他App注冊(cè)與當(dāng)前App一致的intent-filter用于接收廣播,獲取廣播具體信息;
即會(huì)出現(xiàn)安全性 & 效率性的問(wèn)題。
-
解決方案
使用App應(yīng)用內(nèi)廣播(Local Broadcast)- App應(yīng)用內(nèi)廣播可理解為一種局部廣播,廣播的發(fā)送者和接收者都同屬于一個(gè)App。
- 相比于全局廣播(普通廣播),App應(yīng)用內(nèi)廣播優(yōu)勢(shì)體現(xiàn)在:安全性高 & 效率高
-
具體使用1 - 將全局廣播設(shè)置成局部廣播
注冊(cè)廣播時(shí)將exported屬性設(shè)置為false,使得非本App內(nèi)部發(fā)出的此廣播不被接收;
在廣播發(fā)送和接收時(shí),增設(shè)相應(yīng)權(quán)限permission,用于權(quán)限驗(yàn)證;
-
發(fā)送廣播時(shí)指定該廣播接收器所在的包名,此廣播將只會(huì)發(fā)送到此包中的App內(nèi)與之相匹配的有效廣播接收器中。
通過(guò) intent.setPackage(packageName) 指定報(bào)名
-
具體使用2 - 使用封裝好的LocalBroadcastManager類
使用方式上與全局廣播幾乎相同,只是注冊(cè)/取消注冊(cè)廣播接收器和發(fā)送廣播時(shí)將參數(shù)的context變成了LocalBroadcastManager的單一實(shí)例注:對(duì)于LocalBroadcastManager方式發(fā)送的應(yīng)用內(nèi)廣播,只能通過(guò)LocalBroadcastManager動(dòng)態(tài)注冊(cè),不能靜態(tài)注冊(cè)
//注冊(cè)應(yīng)用內(nèi)廣播接收器
//步驟1:實(shí)例化BroadcastReceiver子類 & IntentFilter mBroadcastReceiver
mBroadcastReceiver = new mBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
//步驟2:實(shí)例化LocalBroadcastManager的實(shí)例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//步驟3:設(shè)置接收廣播的類型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
//步驟4:調(diào)用LocalBroadcastManager單一實(shí)例的registerReceiver()方法進(jìn)行動(dòng)態(tài)注冊(cè)
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
//取消注冊(cè)應(yīng)用內(nèi)廣播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
//發(fā)送應(yīng)用內(nèi)廣播
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);
⑤. 粘性廣播(Sticky Broadcast)
由于在Android5.0 & API 21中已經(jīng)失效,所以不建議使用,在這里也不作過(guò)多的總結(jié)。