
目錄

一、Broadcast 的定義
Broadcast 是一種廣泛運(yùn)用的、在應(yīng)用程序之間傳輸信息的機(jī)制,Android 中的廣播與傳統(tǒng)意義上的電臺廣播類似,一個(gè)廣播可以有任意個(gè)接收者,當(dāng)然也可能不被任何應(yīng)用程序所接收。廣播機(jī)制是一個(gè)典型的發(fā)布-訂閱模式,也就是觀察者模式。
廣播機(jī)制最大的特點(diǎn)是發(fā)送方不關(guān)心接收方是否接受到數(shù)據(jù),也不關(guān)心接收方是如何處理數(shù)據(jù)的,通過這樣的方式來達(dá)到接、收雙方的完全解耦。
(一)廣播的三要素:
- 廣播(Broadcast):用于發(fā)送廣播
- 廣播接收器(BroadcastReceiver):用于接收廣播
- 意圖內(nèi)容(Intent):用于保存廣播相關(guān)信息的媒介
(二)廣播的分類:
- 普通廣播
- 有序廣播
- 本地廣播
- Sticky 廣播
二、普通廣播
普通廣播是完全異步的,通過 Context 的 sendBroadcast() 函數(shù)來發(fā)送,消息傳遞的效率比較高,但所有的 receivers(接收器)的執(zhí)行順序不確定。缺點(diǎn)是:接收者不能將處理結(jié)果傳遞給下一個(gè)接收者,并且無法終止廣播 Intent 的傳播,直到?jīng)]有與之匹配的廣播接收器為止。
下面我們來寫一個(gè)普通廣播:
step1:定義一個(gè)廣播接收器
public class MyBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "MyBroadcastReceiver";
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
String name = intent.getStringExtra("name");
Log.d(TAG, name);
}
}
step2:注冊廣播
注冊廣播的方式有兩種:靜態(tài)注冊 和 動態(tài)注冊
- 靜態(tài)注冊:即在 AndroidManifest.xml 文件中進(jìn)行注冊
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.cyy.broad" />
</intent-filter>
</receiver>
enabled 設(shè)置為 true 意味著能夠接受到信息,exported 為 true 意味著能夠接收到外部 apk 廣播發(fā)送的信息。
- 動態(tài)注冊:即在代碼中進(jìn)行注冊
public void registerHelloBroadcast() {
receiver = new MyBroadcastReceiver();
registerReceiver(receiver, new IntentFilter("com.cyy.broad"));
}
如果使用動態(tài)注冊,那么不要忘記在執(zhí)行 onDestroy 時(shí)注銷廣播:
@Override
protected void onDestroy() {
super.onDestroy();
if (receiver != null) {
unregisterReceiver(receiver);
}
}
step3:發(fā)送廣播 sendBroadcast()
如果是靜態(tài)注冊的廣播:
Intent intent = new Intent("com.cyy.broad");
ComponentName componentName = new ComponentName("com.chenyouyu.broadcastdemo",
"com.chenyouyu.broadcastdemo.MyBroadcastReceiver");
intent.setComponent(componentName);
intent.putExtra("name", "hello");
sendBroadcast(intent);
如果是動態(tài)注冊的廣播:
Intent intent = new Intent("com.cyy.broad");
intent.putExtra("name", "hello");
sendBroadcast(intent);
當(dāng)我們調(diào)用了 sendBroadcast() 后,會調(diào)用 MyBroadcastReceiver 的 onReceive 函數(shù)。
三、有序廣播
有序廣播通過 Context.sendOrderedBroadcast() 來發(fā)送,所以的廣播接收器按照優(yōu)先級依次執(zhí)行,廣播接收器的優(yōu)先級通過 receiver 的 intent-filter 中的 android:priority 屬性來設(shè)置,數(shù)值越大優(yōu)先級越高(參數(shù)為 -1000 ~ 1000)。當(dāng)廣播接收器接收到廣播后,可以使用 setResult() 函數(shù)來將結(jié)果傳遞給下一個(gè)廣播接收器,然后通過 getResult() 函數(shù)來取得上一個(gè)廣播接收器返回的結(jié)果,并可以使用 abortBroadcast() 函數(shù)來讓系統(tǒng)丟棄該廣播,使該廣播不再傳遞到別的廣播接收器。
設(shè)置廣播的優(yōu)先級代碼示例:
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.cyy.broad" />
</intent-filter>
</receiver>
關(guān)于 android:priority 的取值范圍,官網(wǎng)給出的是 -1000 ~ 1000 ,但是看到很多人設(shè)置成2147483647(Integer.MAX_VALUE)這個(gè)值,可能因?yàn)?android:priority 的屬性值是 integer 類型,系統(tǒng)會拿這個(gè)值和其他值做比較,結(jié)果怎么都是它最大了。
發(fā)送有序廣播:
sendOrderedBroadcast(intent,null);
四、本地廣播
在 21 版的 Support v4 包中新增本地廣播,也就是 LocalBroadcastManager 。之前廣播都是全局的,所有應(yīng)用程序都可以接收到,這樣就會帶來安全隱患。但是,有的時(shí)候我們并不需要把自己的應(yīng)用內(nèi)的信息廣播給所有應(yīng)用,而只是進(jìn)程內(nèi)使用,現(xiàn)在使用 Support v4 包中的 LocalBroadcastManager 就能夠?qū)崿F(xiàn)限于應(yīng)用內(nèi)的廣播。
它的用法很簡單,只需要把調(diào)用 context 的 sendBroadcast、registerReceiver、unregisterReceiver 的地方替換為 LocalBroadcastManager.getInstance(Context context) 中對應(yīng)的函數(shù)即可:
| 函數(shù) | 作用 |
|---|---|
| LocalBroadcastManager.getInstance(context).registerReceiver(receiver,intentFilter) | 注冊 Receiver |
| LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver) | 注銷 Receiver |
| LocalBroadcastManager.getInstance(context).sendBroadcast(intent) | 發(fā)送異步廣播 |
| LocalBroadcastManager.getInstance(context).sendBroadcastSync(intent) | 發(fā)送同步廣播 |
五、sticky 廣播
sticky 廣播通過 Context.sendStickyBroadcast() 函數(shù)來發(fā)送,用此函數(shù)發(fā)送的廣播會一直滯留,當(dāng)有匹配此廣播的廣播接收器被注冊后,該廣播接收器就會收到此條廣播。使用此函數(shù)發(fā)送廣播時(shí),需要獲得 BROADCAST_STICKY 權(quán)限:
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
sendStickyBroadcast() 只保留最后一條廣播,并且一直保留下去,這樣即使已經(jīng)有廣播接收器處理了該廣播,當(dāng)再有匹配的廣播接收器被注冊時(shí),此廣播仍會被接收。如果你只想處理一遍該廣播,可以通過 removeStickyBroadcast() 函數(shù)實(shí)現(xiàn)。
參考資料:
- 《Android開發(fā)進(jìn)階從小工到專家》何紅輝