Android查缺補漏--BroadcastReceiver的類型與使用
Broadcast 是一種被用於應用內和應用之間傳遞信息的機制。一個廣播可以對應多個接受者。一個完整的廣播機制,需要具有以下三個要素:
- 發送廣播的Broadcast
- 接受廣播的BroadcastReceiver
- 傳遞信息的Intent
廣播的註冊分為靜態註冊和動態註冊:
- 靜態註冊:靜態註冊的廣播是指在AndroidManifest中註冊的廣播,此種廣播在應用安裝時就被系統解析,不需要啟動應用就可以收到相應的廣播。
<receiver android:name=".broadcast.MyBroadcastReceiver"> <intent-filter> <action android:name="MY_BROADCAST_RECEIVER" /> </intent-filter> </receiver>
動態註冊:通過Context.registerReceiver()來實現,不需要時要通過Context.unRegisterReceiver()解除廣播,此種廣播必須應用啟動後才能註冊並接收廣播。
// 動態註冊廣播接收器 registerReceiver(new DynamicBroadcastReceiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
廣播又分為普通廣播、有序廣播、本地廣播和sticky廣播。
一、普通廣播
普通廣播通過Context.sendBroadcast()發送,我們沒有辦法制定Receiver們對於普通廣播的接收順序。理論上所有的接收器(Receiver)接收到廣播的順序不確定,但一般是按照其在AndroidMainfest.xml文件中註冊的順序(不絕對)。
普通廣播中,接受者不能將處理結果傳遞給下一個接收器,也無法終止廣播的傳播。
如下代碼是一個靜態註冊的廣播示例:
public class MyBroadcastReceiver extends BroadcastReceiver { String TAG = MyBroadcastReceiver.class.getSimpleName(); public static final String ACTION = "MY_BROADCAST_RECEIVER"; @Override public void onReceive(Context context, Intent intent) { Log.i(TAG, "接收到廣播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO)); } }
然後再AndroidMainfest.xml中註冊這個廣播:
<receiver android:name=".broadcast.MyBroadcastReceiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
接下來在Activity中調用Context.sendBroadcast()發送廣播就可以了:
Intent intent = new Intent(MyBroadcastReceiver.ACTION);
intent.putExtra(INTENT_INFO, "我是一個普通廣播");
sendBroadcast(intent);
log如下:
12-08 17:29:44.259 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到廣播消息:我是一個普通廣播
- 普通廣播的接收順序測試
我們仿照MyBroadcastReciver創建多個接收器,代碼一樣:
/**
* 靜態註冊的廣播接收器2
* Created by liuwei on 17/12/7.
*/
public class MyBroadcast2Receiver extends BroadcastReceiver {
String TAG = MyBroadcast2Receiver.class.getSimpleName();
public static final String ACTION = "MY_BROADCAST_RECEIVER";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "接收到廣播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
}
}
/**
* 靜態註冊的廣播接收器3
* Created by liuwei on 17/12/7.
*/
public class MyBroadcast3Receiver extends BroadcastReceiver {...}
/**
* 靜態註冊的廣播接收器4
* Created by liuwei on 17/12/7.
*/
public class MyBroadcast4Receiver extends BroadcastReceiver {...}
/**
* 靜態註冊的廣播接收器5
* Created by liuwei on 17/12/7.
*/
public class MyBroadcast5Receiver extends BroadcastReceiver {...}
/**
* 靜態註冊的廣播接收器6
* Created by liuwei on 17/12/7.
*/
public class MyBroadcast6Receiver extends BroadcastReceiver {...}
然後在AndroidMainfest.xml中為以上廣播都註冊同一個action
<receiver android:name=".broadcast.MyBroadcastReceiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast6Receiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast2Receiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast3Receiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast4Receiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast5Receiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
點擊發送廣播,查看log:
12-08 17:29:44.259 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到廣播消息:我是一個普通廣播
12-08 17:29:44.268 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到廣播消息:我是一個普通廣播
12-08 17:29:44.271 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到廣播消息:我是一個普通廣播
12-08 17:29:44.273 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到廣播消息:我是一個普通廣播
12-08 17:29:44.277 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到廣播消息:我是一個普通廣播
12-08 17:29:44.280 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到廣播消息:我是一個普通廣播
二、有序廣播
在AndroidMainfest.xml中註冊廣播時通過priority(值越優先級越高)節點為廣播添加優先級,然後再用Context.sendOrderedBroadcast()發送,接收者們就會按照優先級順序依次執行。
有序廣播的接收者和給下一個接收者傳遞數據,並且接收者在收到廣播之後可以拋棄廣播,使廣播不再向後傳遞。
為上面6個接收器添加優先級:
<receiver android:name=".broadcast.MyBroadcastReceiver">
<intent-filter android:priority="1">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast6Receiver">
<intent-filter android:priority="6">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast2Receiver">
<intent-filter android:priority="2">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast3Receiver">
<intent-filter android:priority="3">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast4Receiver">
<intent-filter android:priority="4">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.MyBroadcast5Receiver">
<intent-filter android:priority="5">
<action android:name="MY_BROADCAST_RECEIVER" />
</intent-filter>
</receiver>
然後通過sendOrderedBroadcast發送廣播觀察log:
intent = new Intent(MyBroadcastReceiver.ACTION);
intent.putExtra(INTENT_INFO, "我是一個有序廣播");
sendOrderedBroadcast(intent, null);
log如下:
12-08 18:17:26.455 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:17:26.462 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:17:26.464 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:17:26.465 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:17:26.466 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:17:26.467 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到廣播消息:我是一個有序廣播
- abortBroadcast()拋棄廣播:
普通的廣播是沒有辦法拋棄的,否則會拋出RuntimeException的異常。
只有有序廣播才可以通過此方法拋棄。我們在MyBroadcast6Receiver中添加abortBroadcast()方法:
public class MyBroadcast6Receiver extends BroadcastReceiver {
String TAG = MyBroadcast6Receiver.class.getSimpleName();
public static final String ACTION = "MY_BROADCAST_RECEIVER";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "接收到廣播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
abortBroadcast();
Log.i(TAG, "丟棄廣播");
}
}
然後點擊發送有序廣播,log如下:
12-08 18:34:27.989 1329-1329/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:34:27.989 1329-1329/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 丟棄廣播
可以看到廣播已經被丟棄了。
- setResult()傳遞給下一個接收者結果。
- getResult()接收上一個接收者的結果。
在MyBroadcast6Receiver中添加setResult方法,在MyBroadcast5Receiver添加getResult方法:
public class MyBroadcast6Receiver extends BroadcastReceiver {
String TAG = MyBroadcast6Receiver.class.getSimpleName();
public static final String ACTION = "MY_BROADCAST_RECEIVER";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "接收到廣播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
// abortBroadcast();
// Log.i(TAG, "丟棄廣播");
setResult(006, "我是老6傳來的消息", null);
}
}
public class MyBroadcast5Receiver extends BroadcastReceiver {
String TAG = MyBroadcast5Receiver.class.getSimpleName();
public static final String ACTION = "MY_BROADCAST_RECEIVER";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "接收到廣播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
String data = getResultData();
Log.i(TAG, "data=" + data);
}
}
log如下:
12-08 18:40:01.415 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:40:01.434 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:40:01.434 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: data=我是老6傳來的消息
12-08 18:40:01.440 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:40:01.442 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:40:01.445 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:40:01.447 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到廣播消息:我是一個有序廣播
三、本地廣播
以上的廣播對於系統來說是全局的,發出廣播後,系統內的應用只要註冊了相應的接收器就都可以收到廣播。如果我們想在本應用發出的廣播只在此應用內可以收到,那麽可以使用本地廣播了。
本地廣播由 LocalBroadcastManager 管理,是在 API 21 以後添加的,使用起來也很方便,需要先通過 LocalBroadcastManager.getInstance() 方法獲取其單例,剩下的用法與其他廣播類似,其主要方法有以下幾個:
- registerReceiver():註冊廣播接收器。
- unregisterReceiver():解除廣播接收器。
- sendBroadcast():發送異步廣播。
- sendBroadcastSync():發送同步廣播。
使用本地廣播時,無需在AndroidMainfest.xml中註冊,必須使用 LocalBroadcastManager.getInstance(...).registerReceiver(..)來註冊接收器。
我們來寫個本地廣播的小栗子,首先註冊兩個本地廣播:
LocalBroadcastManager.getInstance(context).registerReceiver(new MyBroadcastReceiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
LocalBroadcastManager.getInstance(context).registerReceiver(new MyBroadcast2Receiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
然後發送本地廣播:
intent.putExtra(INTENT_INFO, "我是一個本地廣播");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
log如下:
12-09 17:20:47.799 15019-15019/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到廣播消息:我是一個本地廣播
12-09 17:20:47.799 15019-15019/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到廣播消息:我是一個本地廣播
四、sticky廣播(不建議使用)
sticky廣播會一直處於滯留狀態,sticky廣播被發出後,只要有能夠匹配其的新接收器被註冊了就可以收到廣播,sticky廣播通過Context.sendStickyBroadcast()發送。
最後想說的是,本系列文章為博主對Android知識進行再次梳理,查缺補漏的學習過程,一方面是對自己遺忘的東西加以復習重新掌握,另一方面相信在重新學習的過程中定會有巨大的新收獲,如果你也有跟我同樣的想法,不妨關註我一起學習,互相探討,共同進步!
參考文獻:
- 《Android開發藝術探索》
- 《Android開發進階從小工到專家》
Android查缺補漏--BroadcastReceiver的類型與使用