內(nèi)容目錄
- 廣播的定義
- 廣播的用途(
信息傳輸與共享
和通知
) - 廣播的使用場(chǎng)景
- 廣播主要的種類(
普通廣播
诡右、有序廣播
和本地廣播
) - 注冊(cè)廣播接收 (
靜態(tài)接收
和動(dòng)態(tài)接收
) - 廣播的發(fā)送(
sendBroadcast
和sendOrderBroadcast
) - 廣播內(nèi)部實(shí)現(xiàn)機(jī)制
- AMS 是什么卷拘?
- 本地廣播 LocalBroadcastManager
- 全局廣播的缺點(diǎn)
- BroadcastReceiver 和 LocalBroadcastReceiver 區(qū)別
- BroadCastReceiver 的生命周期
- 廣播傳輸?shù)臄?shù)據(jù)是否有限制,是多少,為什么要限制?
1.廣播的定義
- 在 Android 中,Broadcast 是一種在
應(yīng)用程序之間傳輸信息的機(jī)制
斗忌,要發(fā)送的廣播內(nèi)容是一個(gè) Intent,這個(gè) Intent 中可以攜帶我們要傳送的數(shù)據(jù)旺聚。(數(shù)據(jù)小于1MB)
2.廣播的用途
- 廣播實(shí)現(xiàn)了不同程序之間的
信息傳輸與共享
织阳,只要和發(fā)送廣播的 action 相同的接收者,都能接收到這個(gè)廣播砰粹。典型的應(yīng)用就是 android 自帶的短信唧躲,電話等等廣播,只要我們實(shí)現(xiàn)了他們的 action 的廣播碱璃,那么我們就能接收他們的數(shù)據(jù)了弄痹,以便做出一些處理。比如說(shuō)攔截系統(tǒng)短信嵌器,攔截騷擾電話等肛真。 - 作為
通知
的作用,比如在 Service 中要通知主程序爽航、更新主程序的 UI 等蚓让,因?yàn)?Service 是沒(méi)有界面的,所以不能直接獲得主程序中的控件讥珍,這樣我們就只能在主程序中實(shí)現(xiàn)一個(gè)廣播接收者專門用來(lái)接收service發(fā)過(guò)來(lái)的數(shù)據(jù)和通知了历极。
3.廣播的使用場(chǎng)景
- 同一app內(nèi)部的同一組件內(nèi)的消息通信(單個(gè)或多個(gè)線程之間)(可用handler解決);
- 同一app內(nèi)部的不同組件之間的消息通信(單個(gè)進(jìn)程)(可用EventBus)串述;
- 同一app具有多個(gè)進(jìn)程的不同組件之間的消息通信执解;
- 不同app之間的組件之間的消息通信;
- Android系統(tǒng)在特定情況下與App之間的消息通信纲酗。
4.廣播主要的種類
普通廣播Normal Broadcast:
異步
執(zhí)行的廣播衰腌,所有接收者在同一時(shí)刻收到這條廣播消息。效率高觅赊,沒(méi)有先后順序右蕊,無(wú)法截?cái)唷儆谌謴V播吮螺。調(diào)用sendBroadcast()
發(fā)送饶囚,最常用的廣播帕翻。有序廣播Ordered Broadcast:
同步
執(zhí)行的廣播,發(fā)出去的廣播會(huì)被廣播接收者按照順序接收萝风,廣播接收者按照Priority屬性值從大-小排序嘀掸,Priority屬性相同者,動(dòng)態(tài)注冊(cè)的廣播優(yōu)先规惰,廣播接收者還可以選擇對(duì)廣播進(jìn)行截?cái)嗪托薷牟撬U{(diào)用sendOrderedBroadcast()
發(fā)送。本地廣播Local Broadcast:App應(yīng)用內(nèi)廣播可理解為一種
局部廣播
歇万,廣播的發(fā)送者和接收者都同屬于一個(gè)App揩晴。相比于全局廣播(普通廣播),App應(yīng)用內(nèi)廣播優(yōu)勢(shì)體現(xiàn)在:安全性高 & 效率高贪磺。對(duì)于LocalBroadcastManager方式發(fā)送的應(yīng)用內(nèi)廣播硫兰,只能通過(guò)LocalBroadcastManager動(dòng)態(tài)注冊(cè)
,不能靜態(tài)注冊(cè)寒锚。調(diào)用sendBroadcast
發(fā)送劫映。
4、注冊(cè)廣播接收 (靜態(tài)和動(dòng)態(tài))
4.1兩種注冊(cè)方法的區(qū)別
-
動(dòng)態(tài)注冊(cè)的接收器必須要在程序
啟動(dòng)之后才能
接收到廣播壕曼; -
靜態(tài)注冊(cè)的接收器即便程序
未啟動(dòng)也能
接收到廣播苏研,比如想接收到手機(jī)開機(jī)完成后系統(tǒng)發(fā)出的廣播就只能用靜態(tài)注冊(cè)了。
4.2靜態(tài)注冊(cè)具體步驟
- 靜態(tài)注冊(cè):將廣播寫在 AndroidMainifest.xml 文件當(dāng)中腮郊,特點(diǎn)是:常駐系統(tǒng)摹蘑,不受組件生命周期影響,即便應(yīng)用退出轧飞,廣播還是可以被接收衅鹿,耗電、占內(nèi)存过咬。
- 第一步:
創(chuàng)建繼承 BroadcastReceiver
大渤,然后重寫具體實(shí)現(xiàn)onReceive(),由于生命周期短掸绞,耗時(shí)工作應(yīng)該發(fā)給Service泵三,onReceive()不要開啟子線程。
public class MyReceiver extends BroadcastReceiver {
//onReceive 不能做過(guò)多的耗時(shí)操作衔掸,10秒沒(méi)響應(yīng)就ANR
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "boot complete", Toast.LENGTH_SHORT).show();
}
}
- 第二步:
在 AndroidMainifest.xml 中添加<receiver>
烫幕,子標(biāo)簽intent-filter中添加需要監(jiān)聽的action。Exported 屬性表示是否允許這個(gè)廣播接收本程序以外的廣播敞映,Enabled 屬性表示是否啟用用這個(gè)廣播接收器较曼。
<receiver
android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
4.3 動(dòng)態(tài)注冊(cè)
-
動(dòng)態(tài)注冊(cè) : 自定義類繼承 BroadcastReceiver,然后重寫具體實(shí)現(xiàn)onReceive()振愿。在代碼中調(diào)用
registerReceiver()
注冊(cè)來(lái)進(jìn)行廣播的注冊(cè)捷犹。必須在 onDestroy 中調(diào)用unregisterReceiver()
方法弛饭,否則會(huì)引起內(nèi)存泄露。特點(diǎn)是:不常駐萍歉,跟隨組件的生命變化侣颂,組件結(jié)束,廣播結(jié)束枪孩。在組件結(jié)束前横蜒,需要先移除廣播,否則容易造成內(nèi)存泄漏销凑。
protected void onCreate() {
myBroadcastReceiver ChangeReceiver = new myBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(ChangeReceiver, intentFilter);
}
//在onDestroy()中要取消注冊(cè),否則會(huì)引起內(nèi)存泄漏仅炊。
protected void onDestroy() {
unregisterReceiver(networkChangeReceiver);
}
//ChangeReceiver就是接收后會(huì)怎么樣怎么樣
class myBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent){
//to do
}
}
5斗幼、廣播的發(fā)送
1.標(biāo)準(zhǔn)廣播(異步)
//通過(guò)sendBroadcast發(fā)送標(biāo)準(zhǔn)合家歡廣播
Intent intent = new Intent("com.example.songsong.MY_BROADCAST");
sendBroadcast(intent);
2.有序廣播(同步)
- 定義:發(fā)送出去的廣播被廣播接收者按照先后順序接收
- 接收廣播的順序規(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)?/code>呆馁,即后接收的廣播接收者不再接收到此廣播桐经;
- 先接收的廣播接收者可以對(duì)廣播進(jìn)行
修改
,那么后接收的廣播接收者將接收到被修改后的廣播
//通過(guò)sendOrderBroadcast發(fā)送
Intent intent = new Intent("com.example.songsong.MY_BROADCAST");
sendOrderBroadcast(intent,null);
/*給廣播接收器設(shè)置優(yōu)先級(jí) */
<intent-filter android:priority="100">
<action android:name="com.example.broadcasttest.LOCAL_BROADCAST" />
</intent-filter>
//廣播接收器截?cái)啵?public void onReceive(Context context, Intent intent) {
abortBroadcast();
}
3.本地廣播
//發(fā)送1:實(shí)例化localBroadcastManager
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
//發(fā)送2:發(fā)送廣播
Intent intent = new Intent("android.net.conn.CONNECTIVITY_CHANGE");
localBroadcastManager.sendBroadcast(intent);
//接收1:實(shí)例化IntentFilter和接收器LocalReceiver
IntentFilter intentFilter = new IntentFilter();
LocalReceiver localReceiver = new LocalReceiver();
//接收2:設(shè)置廣播接收類型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
//接收3:進(jìn)行動(dòng)態(tài)注冊(cè)本地廣播
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
//接收4:在onDestroy中取消注冊(cè)
localBroadcastManager.unregisterReceiver(localReceiver);
//接收5:在localReceiver中繼承BroadcastReceiver并重寫onReceiver浙滤。
...
6.廣播內(nèi)部實(shí)現(xiàn)機(jī)制
- 自定義廣播接收者 BroadcastReceiver阴挣,并復(fù)寫 onRecvice();
- 通過(guò) Binder 機(jī)制向 AMS(Activity Manager Service) 注冊(cè)廣播;
- 通過(guò) Binder 機(jī)制向 AMS(Activity Manager Service) 發(fā)送廣播纺腊。
- AMS 查找符合相應(yīng)條件(IntentFilter/Permission等)的BroadcastReceiver畔咧,將廣播發(fā)送到BroadcastReceiver 所在的消息循環(huán)隊(duì)列中。
- BroadcastReceiver 所在消息隊(duì)列拿到此廣播后揖膜,回調(diào)它的 onReceive() 方法誓沸。
7.AMS 是什么?
AMS(Activity Manager Service):是貫穿Android系統(tǒng)組件的核心服務(wù)壹粟,負(fù)責(zé)啟動(dòng)四大組件啟動(dòng)切換調(diào)度拜隧。
8.本地廣播 LocalBroadcastManager
背景:Android中的廣播可以跨App直接通信(exported對(duì)于有intent-filter情況下默認(rèn)值為true)
-
沖突:
- 其他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)在:安全性高 & 效率高坐儿;
-
特點(diǎn):
- 發(fā)送的廣播只能夠在自己 App 的內(nèi)部傳遞律胀,不會(huì)泄露給其他 App宋光,確保隱私數(shù)據(jù)不會(huì)泄露;
- 廣播接收器只能接收來(lái)自本 App 發(fā)出的廣播炭菌;
- 其他App也無(wú)法向你的App發(fā)送該廣播罪佳,不用擔(dān)心其他App會(huì)來(lái)搞破壞;
- 比系統(tǒng)的全局廣播更加高效黑低。
-
內(nèi)部實(shí)現(xiàn)原理:
-
LocalBroadcastManager
高效的原因主要因?yàn)樗鼉?nèi)部是通過(guò)Handler
實(shí)現(xiàn)的赘艳,它的sendBroadcast()
方法是通過(guò)handler()
發(fā)送一個(gè)Message
實(shí)現(xiàn)的。 - 相比系統(tǒng)廣播是通過(guò)
Binder
實(shí)現(xiàn)的克握,本地廣播會(huì)更加高效蕾管。別人應(yīng)用無(wú)法向自己的App發(fā)送廣播,而自己App發(fā)送的廣播也不會(huì)離開自己的App菩暗。 - LocalBroadcastManager 內(nèi)部協(xié)作主要是靠?jī)蓚€(gè)Map集合:
mReceivers
和mActions
掰曾,當(dāng)然還有一個(gè)List集合mPendingBroadcasts
,主要是存儲(chǔ)待接收的廣播對(duì)象停团。
-
9.全局廣播的缺點(diǎn)
- App被反編譯獲得Action后旷坦,會(huì)被植入廣告、數(shù)據(jù)泄露佑稠。
10.BroadcastReceiver 和 LocalBroadcastReceiver 區(qū)別
-
BroadcastReceiver 是
跨應(yīng)用
廣播秒梅,利用Binder
機(jī)制實(shí)現(xiàn)。 -
LocalBroadcastReceiver 是
應(yīng)用內(nèi)
廣播舌胶,利用Handler
實(shí)現(xiàn)捆蜀,利用了IntentFilter的match功能,提供消息的發(fā)布與接收功能辆琅,實(shí)現(xiàn)應(yīng)用內(nèi)通信漱办,效率比較高。
11.Broadcast Receiver能在onReceive中執(zhí)行耗時(shí)任務(wù)嗎婉烟?
BroadcastReceiver 在 10 秒
內(nèi)沒(méi)有執(zhí)行完畢娩井,Android 會(huì)認(rèn)為該程序無(wú)響應(yīng)ANR,所以在 onReceive 通常是不能開啟線程的似袁,一般是通過(guò) service 或者 IntentService
來(lái)處理洞辣。
12.BroadCastReceiver 的生命周期
- a. 廣播接收者的生命周期非常短暫的,在接收到廣播的時(shí)候創(chuàng)建昙衅,onReceive()方法結(jié)束之后銷毀扬霜;
- b. 廣播接收者中不要做一些耗時(shí)的工作,否則會(huì)彈出 Application No Response應(yīng)用無(wú)響應(yīng)對(duì)話框而涉;
- c. 最好也不要在廣播接收者中創(chuàng)建子線程做耗時(shí)的工作著瓶,因?yàn)閺V播接收者被銷毀后進(jìn)程就成為了空進(jìn)程,很容易被系統(tǒng)殺掉啼县;
- d. 耗時(shí)的較長(zhǎng)的工作最好放在服務(wù)中完成材原;
13.廣播傳輸?shù)臄?shù)據(jù)是否有限制沸久,是多少,為什么要限制余蟹?
Broadcast廣播通過(guò)Intent來(lái)傳輸數(shù)據(jù)卷胯,而Intent的數(shù)據(jù)大小限制為小于1MB,如果大于等于1MB都會(huì)出現(xiàn)異常威酒。
Intent攜帶信息的大小其實(shí)是受Binder限制窑睁,Binder傳遞緩存有一個(gè)限定大小,通常是1Mb葵孤。但同一個(gè)進(jìn)程中所有的
傳輸共享緩存空間
担钮。多個(gè)地方在進(jìn)行傳輸時(shí),即時(shí)它們各自傳輸?shù)臄?shù)據(jù)不超出大小限制尤仍,TransactionTooLargeException
異常也可能會(huì)被拋出裳朋。參考文章:https://blog.csdn.net/u011033906/article/details/89316543
本文參考資料:
- 《Android開發(fā)藝術(shù)探索》
- 《第一行代碼》
- http://www.reibang.com/p/718aa3c1a70b
- Fragment通信參考文章:https://juejin.im/entry/59746af7f265da6c34337d2e