內(nèi)容目錄
- 廣播的定義
- 廣播的用途(
信息傳輸與共享和通知) - 廣播的使用場景
- 廣播主要的種類(
普通廣播、有序廣播和本地廣播) - 注冊廣播接收 (
靜態(tài)接收和動態(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ù)了,以便做出一些處理。比如說攔截系統(tǒng)短信,攔截騷擾電話等。 - 作為
通知的作用,比如在 Service 中要通知主程序、更新主程序的 UI 等,因?yàn)?Service 是沒有界面的,所以不能直接獲得主程序中的控件,這樣我們就只能在主程序中實(shí)現(xiàn)一個(gè)廣播接收者專門用來接收service發(fā)過來的數(shù)據(jù)和通知了。
3.廣播的使用場景
- 同一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í)刻收到這條廣播消息。效率高,沒有先后順序,無法截?cái)?。屬于全局廣播。調(diào)用sendBroadcast()發(fā)送,最常用的廣播。有序廣播Ordered Broadcast:
同步執(zhí)行的廣播,發(fā)出去的廣播會被廣播接收者按照順序接收,廣播接收者按照Priority屬性值從大-小排序,Priority屬性相同者,動態(tài)注冊的廣播優(yōu)先,廣播接收者還可以選擇對廣播進(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)勢體現(xiàn)在:安全性高 & 效率高。對于LocalBroadcastManager方式發(fā)送的應(yīng)用內(nèi)廣播,只能通過LocalBroadcastManager動態(tài)注冊,不能靜態(tài)注冊。調(diào)用sendBroadcast發(fā)送。
4、注冊廣播接收 (靜態(tài)和動態(tài))
4.1兩種注冊方法的區(qū)別
-
動態(tài)注冊的接收器必須要在程序
啟動之后才能接收到廣播; -
靜態(tài)注冊的接收器即便程序
未啟動也能接收到廣播,比如想接收到手機(jī)開機(jī)完成后系統(tǒng)發(fā)出的廣播就只能用靜態(tài)注冊了。
4.2靜態(tài)注冊具體步驟
- 靜態(tài)注冊:將廣播寫在 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 不能做過多的耗時(shí)操作,10秒沒響應(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 動態(tài)注冊
-
動態(tài)注冊 : 自定義類繼承 BroadcastReceiver,然后重寫具體實(shí)現(xiàn)onReceive()。在代碼中調(diào)用
registerReceiver()注冊來進(jìn)行廣播的注冊。必須在 onDestroy 中調(diào)用unregisterReceiver()方法,否則會引起內(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()中要取消注冊,否則會引起內(nèi)存泄漏。
protected void onDestroy() {
unregisterReceiver(networkChangeReceiver);
}
//ChangeReceiver就是接收后會怎么樣怎么樣
class myBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent){
//to do
}
}
5、廣播的發(fā)送
1.標(biāo)準(zhǔn)廣播(異步)
//通過sendBroadcast發(fā)送標(biāo)準(zhǔn)合家歡廣播
Intent intent = new Intent("com.example.songsong.MY_BROADCAST");
sendBroadcast(intent);
2.有序廣播(同步)
- 定義:發(fā)送出去的廣播被廣播接收者按照先后順序接收
- 接收廣播的順序規(guī)則(同時(shí)面向靜態(tài)和動態(tài)注冊的廣播接受者)
- 按照
Priority屬性值從大-小排序; -
Priority屬性相同者,動態(tài)注冊的廣播優(yōu)先;
- 按照
- 特點(diǎn):
- 接收廣播按順序接收;
- 先接收的廣播接收者可以對廣播進(jìn)行
截?cái)?/code>,即后接收的廣播接收者不再接收到此廣播; - 先接收的廣播接收者可以對廣播進(jìn)行
修改,那么后接收的廣播接收者將接收到被修改后的廣播
//通過sendOrderBroadcast發(fā)送
Intent intent = new Intent("com.example.songsong.MY_BROADCAST");
sendOrderBroadcast(intent,null);
/*給廣播接收器設(shè)置優(yōu)先級 */
<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)行動態(tài)注冊本地廣播
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
//接收4:在onDestroy中取消注冊
localBroadcastManager.unregisterReceiver(localReceiver);
//接收5:在localReceiver中繼承BroadcastReceiver并重寫onReceiver。
...
6.廣播內(nèi)部實(shí)現(xiàn)機(jī)制
- 自定義廣播接收者 BroadcastReceiver,并復(fù)寫 onRecvice();
- 通過 Binder 機(jī)制向 AMS(Activity Manager Service) 注冊廣播;
- 通過 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é)啟動四大組件啟動切換調(diào)度。
8.本地廣播 LocalBroadcastManager
背景:Android中的廣播可以跨App直接通信(exported對于有intent-filter情況下默認(rèn)值為true)
-
沖突:
- 其他App針對性發(fā)出與當(dāng)前App intent-filter相匹配的廣播,由此導(dǎo)致當(dāng)前App不斷接收廣播并處理;
- 其他App注冊與當(dāng)前App一致的intent-filter用于接收廣播,獲取廣播具體信息(即會出現(xiàn)安全性 & 效率性的問題)。
-
解決方案:使用App應(yīng)用內(nèi)廣播(Local Broadcast)
- App應(yīng)用內(nèi)廣播可理解為一種局部廣播,廣播的發(fā)送者和接收者都同屬于一個(gè)App。
- 相比于全局廣播(普通廣播),App應(yīng)用內(nèi)廣播優(yōu)勢體現(xiàn)在:安全性高 & 效率高;
-
特點(diǎn):
- 發(fā)送的廣播只能夠在自己 App 的內(nèi)部傳遞,不會泄露給其他 App,確保隱私數(shù)據(jù)不會泄露;
- 廣播接收器只能接收來自本 App 發(fā)出的廣播;
- 其他App也無法向你的App發(fā)送該廣播,不用擔(dān)心其他App會來搞破壞;
- 比系統(tǒng)的全局廣播更加高效。
-
內(nèi)部實(shí)現(xiàn)原理:
-
LocalBroadcastManager高效的原因主要因?yàn)樗鼉?nèi)部是通過Handler實(shí)現(xiàn)的,它的sendBroadcast()方法是通過handler()發(fā)送一個(gè)Message實(shí)現(xiàn)的。 - 相比系統(tǒng)廣播是通過
Binder實(shí)現(xiàn)的,本地廣播會更加高效。別人應(yīng)用無法向自己的App發(fā)送廣播,而自己App發(fā)送的廣播也不會離開自己的App。 - LocalBroadcastManager 內(nèi)部協(xié)作主要是靠兩個(gè)Map集合:
mReceivers和mActions,當(dāng)然還有一個(gè)List集合mPendingBroadcasts,主要是存儲待接收的廣播對象。
-
9.全局廣播的缺點(diǎn)
- App被反編譯獲得Action后,會被植入廣告、數(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)沒有執(zhí)行完畢,Android 會認(rèn)為該程序無響應(yīng)ANR,所以在 onReceive 通常是不能開啟線程的,一般是通過 service 或者 IntentService 來處理。
12.BroadCastReceiver 的生命周期
- a. 廣播接收者的生命周期非常短暫的,在接收到廣播的時(shí)候創(chuàng)建,onReceive()方法結(jié)束之后銷毀;
- b. 廣播接收者中不要做一些耗時(shí)的工作,否則會彈出 Application No Response應(yīng)用無響應(yīng)對話框;
- c. 最好也不要在廣播接收者中創(chuàng)建子線程做耗時(shí)的工作,因?yàn)閺V播接收者被銷毀后進(jìn)程就成為了空進(jìn)程,很容易被系統(tǒng)殺掉;
- d. 耗時(shí)的較長的工作最好放在服務(wù)中完成;
13.廣播傳輸?shù)臄?shù)據(jù)是否有限制,是多少,為什么要限制?
Broadcast廣播通過Intent來傳輸數(shù)據(jù),而Intent的數(shù)據(jù)大小限制為小于1MB,如果大于等于1MB都會出現(xiàn)異常。
Intent攜帶信息的大小其實(shí)是受Binder限制,Binder傳遞緩存有一個(gè)限定大小,通常是1Mb。但同一個(gè)進(jìn)程中所有的
傳輸共享緩存空間。多個(gè)地方在進(jìn)行傳輸時(shí),即時(shí)它們各自傳輸?shù)臄?shù)據(jù)不超出大小限制,TransactionTooLargeException異常也可能會被拋出。參考文章:https://blog.csdn.net/u011033906/article/details/89316543
本文參考資料:
- 《Android開發(fā)藝術(shù)探索》
- 《第一行代碼》
- http://www.itdecent.cn/p/718aa3c1a70b
- Fragment通信參考文章:https://juejin.im/entry/59746af7f265da6c34337d2e