詳解 Android 中的廣播機制
前言
Android 中的每個應用程序都可以對自己感興趣的廣播進行注冊,這樣該程序就只會接受自己所關心的廣播內(nèi)容,這些廣播內(nèi)容可能是來自于系統(tǒng),也可能是來自于其他應用程序的;
Android 提供了一整套的 API,允許應用程序自由地發(fā)送和接受廣播
今天我們就來詳細介紹下
一. 廣播介紹
1、標準廣播
- 這是一種完全異步執(zhí)行的廣播,在廣播發(fā)出之后,所有的廣播接收器幾乎都會在同一時刻接收到這條廣播消息,因此它們之間沒有任何先后順序可言。接收器不能對收到的廣播做任何處理,也不能截斷廣播繼續(xù)傳播;
- 該種類的廣播用sendBroadcast發(fā)送;
2、有序廣播
- 這是一種同步執(zhí)行的廣播,在廣播發(fā)出之后,同一時刻只會有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執(zhí)行完畢后,廣播才會繼續(xù)傳遞;
- 所以此時的廣播接收器是有先后順序的,優(yōu)先級高的廣播接收器就可以先收到廣播消息,并且前面的廣播接收器還可以截斷正在傳遞的廣播,這樣后面的廣播接收器就無法收到廣播消息了;
- 該種類的廣播用sendOrderedBroadcast發(fā)送;
3、粘性廣播
- 粘性廣播的特點是Intent會一直保留到廣播事件結(jié)束,而這種廣播也沒有所謂的10秒限制,10秒限制是指普通的廣播如果onReceive方法執(zhí)行時間太長,超過10秒的時候系統(tǒng)會將這個廣播置為可以被干掉的‘候選人’,一旦系統(tǒng)資源不夠的時候,就會干掉這個廣播而讓它不執(zhí)行。該廣播用sendStickyBroadcast發(fā)送;
- 在Android5.0 & API 21中已經(jīng)失效,所以不建議使用;
二、廣播詳解
Android 內(nèi)置了很多系統(tǒng)級別的廣播,我們可以在應用中通過監(jiān)聽這些廣播來得到各種系統(tǒng)的狀態(tài)信息。比如手機開機后會發(fā)送一條廣播,電池的電量發(fā)生變化會發(fā)出一條廣播,時間或時區(qū)發(fā)生改變也會發(fā)出一條廣播等等;
注冊廣播方式一般有兩種:
動態(tài)注冊在代碼中注冊;
靜態(tài)注冊在 AndroidManifest.xml 中注冊
1、靜態(tài)注冊
一般為常駐廣播,在AndroidManifest.xml里通過
- <receiver android:name=".MyBroadcastReceiver" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED"/>
- <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
- </intent-filter>
- </receiver>
intent過濾器里指定的是接收器訂閱的action;
2、動態(tài)注冊
非常駐廣播,在使用時注冊,用完及時銷毀;
- BroadcastReceiver br = new MyBroadcastReceiver();
- IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
- filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- this.registerReceiver(br, filter);
記得及時注銷,以免內(nèi)存泄漏;
- @Override
- protected void onDestroy() {
- super.onDestroy();
- unregisterReceiver(receiver);
- }
3、自定義廣播
注冊廣播
- <receiver
- android:name=".test.MyBroadcastReceiver"
- android:enabled="true"
- android:exported="true">
- <intent-filter>
- <action android:name="com.test.test" />
- </intent-filter>
- </receiver>
- public class MyBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Toast.makeText(context,"發(fā)送標準廣播",Toast.LENGTH_LONG).show();
- }
- }
- Intent intent = new Intent("com.test.test");
- sendBroadcast(intent);
- //發(fā)送有序廣播
- Intent intent = new Intent("com.test.test");
- sendOrderedBroadcast(intent,null);
4、本地廣播
我們發(fā)送和接受的廣播全部屬于系統(tǒng)全局廣播,即發(fā)出的廣播可以被其它任何應用程序接收到,并且我們也可以接受來自于其它任何應用程序的廣播;
為了解決廣播安全性問題,Android 引入了一套本地廣播機制,使用這個機制發(fā)出的廣播只能在應用程序內(nèi)部進行傳遞,并且廣播接受器也只能接受來自本應用程序發(fā)出的廣播,這樣所有的安全性問題就都不存在了;
初始化廣播:
- private LocalBroadcastManager localBroadcastManager;
- private void init() {
- //獲取實例
- localBroadcastManager = LocalBroadcastManager.getInstance(this);
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction("om.test.LOCAL_BROADCAST");
- LocalReceiver localReceiver = new LocalReceiver();
- localBroadcastManager.registerReceiver(localReceiver, intentFilter);
- }
- Intent intent = new Intent("om.test.LOCAL_BROADCAST");
- localBroadcastManager.sendBroadcast(intent);
- 定義
- private class LocalReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Toast.makeText(context, "本地廣播.....", Toast.LENGTH_LONG).show();
- }
- }
優(yōu)點:
- 可以明確知道正在發(fā)送的廣播不會離開我們的程序,因此不必擔心機密數(shù)據(jù)泄露:
- 其它的程序無法將廣播發(fā)送到我們程序內(nèi)部,因此不需要擔心會有安全漏洞問題:
- 發(fā)送本地廣播比發(fā)送系統(tǒng)全局廣播更加高效:
5、帶權(quán)限的標準廣播
發(fā)廣播
當調(diào)用sendBroadcast(Intent, String)或sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)時,可以指定權(quán)限參數(shù);
- sendBroadcast(new Intent("com.test"),
- Manifest.permission.SEND_SMS);
要想接收這個廣播,那么這個接收的app必須申請該權(quán)限
- <uses-permission android:name="android.permission.SEND_SMS"/>
接收廣播
如果在注冊廣播接收器時指定了權(quán)限參數(shù)(使用registerReceiver(BroadcastReceiver,IntentFilter,String,Handler)或清單文件中的
在清單文件中聲明:
- <receiver android:name=".MyBroadcastReceiver"
- android:permission="android.permission.SEND_SMS">
- <intent-filter>
- <action android:name="com.test"/>
- </intent-filter>
- </receiver>
在注冊的時候聲明:
- IntentFilter filter = new IntentFilter("com.test);
- registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null );
要給它發(fā)消息,那廣播發(fā)送的app就必須得申請獲得相應的權(quán)限才行:
- <uses-permission android:name="android.permission.SEND_SMS"/>
總結(jié)
動態(tài)注冊廣播不是常駐型廣播,也就是說廣播跟隨Activity的生命周期。注意在Activity結(jié)束前,移除廣播接收器;
靜態(tài)注冊是常駐型,也就是說當應用程序關閉后,如果有信息廣播來,程序也會被系統(tǒng)調(diào)用自動運行;
當廣播為有序廣播時:優(yōu)先級高的先接收(不分靜態(tài)和動態(tài))。同優(yōu)先級的廣播接收器,動態(tài)優(yōu)先于靜態(tài);
同優(yōu)先級的同類廣播接收器,靜態(tài):先掃描的優(yōu)先于后掃描的,動態(tài):先注冊的優(yōu)先于后注冊的;
當廣播為默認廣播時:無視優(yōu)先級,動態(tài)廣播接收器優(yōu)先于靜態(tài)廣播接收器。同優(yōu)先級的同類廣播接收器,靜態(tài):先掃描的優(yōu)先于后掃描的,動態(tài):先注冊的優(yōu)先于后冊的;
本文轉(zhuǎn)載自微信公眾號「Android開發(fā)編程」