
1、廣播實作原理
Android 中的廣播使用了設計模式中的觀察者模式:基于消息的釋出/訂閱事件模型。
模型中有3個角色:1. 消息訂閱者(廣播接收者) 2. 消息釋出者(廣播釋出者) 3. 消息中心( AMS ,即 Activity Manager Service )
原理描述:
1. 廣播接收者 通過 Binder 機制在 AMS 注冊
2. 廣播發送者 通過 Binder 機制向 AMS 發送廣播
3. AMS 根據 廣播發送者 要求,在已注冊清單中,尋找合适的廣播接收者
尋找依據:IntentFilter / Permission
4. AMS 将廣播發送到合适的廣播接收者相應的消息循環隊列中;
5. 廣播接收者通過 消息循環 拿到此廣播,并回調 onReceive()
特别注意:廣播發送者 和 廣播接收者的執行 是 異步的,發出去的廣播不會關心有無接收者接收,也不确定接收者到底是何時才能接收到;
2、廣播的分類
- 無序廣播
也就是最常見的标準廣播,通過SendBroadcast()方法發送。
- 有序廣播
針對廣播接收方而言,通過sendOrderedBroadcast(intent)發送,發送出去的廣播被廣播接收者按照優先級先後順序接收,相同優先級的動态注冊的廣播優先,每次隻能有一個接受者收到,接受者收到廣播後,可以通過setResultData來傳遞資料給下一個接收者,也可以通過abortBroadcast()來終止廣播繼續向下傳遞。
- 粘性廣播
調用SendStickyBroadcast()方法發送,需要android.Manifest.permission.BROADCAST_STICKT權限,注冊者可以接受到注冊廣播前發送者發送的最後一次廣播。目前API 21中已标記為Deprecated,不推薦使用。系統中電量的廣播就是使用粘性廣播發送的。
- 本地廣播
通過系統LocalBroadcastManager發送,隻能在目前應用内接收。相對于其他類型廣播而言,安全性高&效率高。本地廣播隻能通過LocalBroadcastManager動态注冊。
- 系統廣播
有的地方把這個也算一個分類,這裡也提一下,系統廣播就是Android系統内置的廣播,用來通知應用一些系統狀态的改變,如:息屏亮屏,電量變化,網絡狀态變化。使用者隻需注冊對應的Action, 系統有相關操作時會自動廣播。
3、廣播注冊的方式
- 靜态注冊
在Manifest檔案中,通過xml标簽注冊。
<receiver android:name=".XXXReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter></receiver>
複制
exported屬性表示是否暴露給其他應用,設定為true, 則可以接收到其他應用發送的廣播,預設值是由BroadcastReceiver中有無Intent-filter決定的,如果有Intent-filter,預設值為true,否則為false。
上面例子中,當此App首次啟動時,系統會自動執行個體化XXXReceiver類,并注冊到系統中。
- 動态注冊
在代碼中通過調用Context的registerReceiver()方法進行動态注冊
@Override protected void onResume() { super.onResume(); //執行個體化BroadcastReceiver子類 & IntentFilter mBroadcastReceiver mBroadcastReceiver = new mBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); //設定接收廣播的類型 intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE) ; //調用Context的registerReceiver()方法進行動态注冊 registerReceiver(mBroadcastReceiver, intentFilter); }
複制
動态注冊時要注意注冊與反注冊成對出現,否則會造成記憶體洩漏。
4、兩種廣播注冊方式的比較
5、LocalBroadcastManager實作原理
LocalBroadcastManager雖然使用和普通廣播沒有太大差别,但是原理卻是完全不同。LocalBroadcastManager内部維護了mReceivers和mActions兩個HashMap,
mReceivers 是接收器和IntentFilter的對應表,主要作用是友善在unregisterReceiver(…)取消注冊,同時作為對象鎖限制注冊接收器、發送廣播、取消接收器注冊等幾個過程的并發通路。
mActions 以Action為 key,注冊這個Action的BroadcastReceiver連結清單為 value。mActions 的主要作用是友善在廣播發送後快速得到可以接收它的BroadcastReceiver。
在注冊廣播時,其實是在更新這兩個Map.
HashMap<BroadcastReceiver, ArrayList<IntentFilter>> mReceivers = new HashMap<BroadcastReceiver, ArrayList<IntentFilter>>();HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<String, ArrayList<ReceiverRecord>>();
複制
發送廣播時,根據Action從mActions中取出ReceiverRecord清單,找出action比對的廣播,然後通過Handler發送消息,在Handler的handleMessage中,取出比對的廣播清單,依次回調onReceive方法。
6、常見系統廣播
監聽網絡變化 | android.net.conn.CONNECTIVITY_CHANGE |
---|---|
電量發生變化 | ACTION_BATTERY_CHANGED |
成功安裝APK | ACTION_PACKAGE_ADDED |
息屏/亮屏 | ACTION_SCREEN_OFF/ON |
系統啟動完成 | ACTION_BOOT_COMPLETED |
時間變化(每分鐘1次) | ACTION_TIME_TICK |
從Android 7.0開始,系統不會再發送廣播ACTION_NEW_PICTURE和ACTION_NEW_VIDEO,對于廣播CONNECTIVITY_ACTION必須在代碼中使用registerReceiver方法注冊接收器,在AndroidManifest檔案中聲明接收器不起作用。
從Android 8.0開始,對于大多數系統隐式廣播,不能在AndroidManifest檔案中注冊。
7、廣播安全性
Android系統中的廣播可以跨程序直接通信,會産生以下兩個問題:
其他APP可以接收到目前APP發送的廣播,導緻資料外洩。
其他APP可以向目前APP放廣播消息,導緻APP被非法控制。
(1)發送廣播
- 發送廣播時,增加相應的permission,用于權限驗證。
- 在Android 4.0及以上系統中發送廣播時,可以使用setPackage()方法設定接受廣播的包名。
- 使用本地廣播。
(2)接受廣播
- 注冊廣播接收器時,增加相應的permission,用于權限驗證。
- 注冊廣播接收器時,設定android:exported的值為false。
- 使用本地廣播。
發送廣播時,如果增加了permission,那接受廣播的APP必須申請相應權限,這樣才能收到對應的廣播,反之亦然。
8、廣播中能執行耗時操作嗎?
不能,廣播接收預設是在主線程中運作,在前面Android高頻面試專題 - 進階篇(一)ANR中講過,廣播逾時是10s(前台)和60s(背景),如果耗時超過這個時間,就會抛出ANR,是以如果需要在廣播内執行耗時操作,可以在廣播内啟動一個IntentService來執行。