Android中BroadcastReceiver系列
广播的注册方式
- 动态注册(代码注册)
动态注册的广播会受Activity的生命周期的影响, 当Activity销毁的时候,广播就失效了。本地广播只能通过动态注册来接收,相比起系统全局广播更加高效 - 静态注册(清单文件注册)
而静态注册的广播,即使Activity销毁了,仍然可以收到广播。更牛掰的是即使杀死进程,仍然可以收到广播。
有序广播和普通广播
-
有序广播(Ordered Broadcast)
一、优缺点
优点:
1、按优先级的不同,优先Receive可对数据进行处理,并传给下一个Receiver
2、通过abortBroadcast可终止广播的传播
缺点:效率低
二、发送广播的方法:sendOrderedBroadcast()
三、优先接收到Broadcast的Receiver可通过setResultExtras(Bundle)方法将处理结果存入Broadcast中,下一个Receiver 通过 Bundle bundle=getResultExtras(true)方法获取上一个 Receiver传来的数据
-
普通广播(Normal Broadcast)
一、优缺点:和有序广播的优缺点相反!
二、发送广播的方法:sendBroadcast()
本地广播和全局广播
一、区别
1、本地广播:发送的广播事件不被其他应用程序获取,也不能响应其他应用程序发送的广播事件。本地广播只能被动态注册,不能静态注册。动态注册或方法时需要用到LocalBroadcastManager。
2、全局广播:发送的广播事件可被其他应用程序获取,也能响应其他应用程序发送的广播事件(可以通过 exported–是否监听其他应用程序发送的广播 在清单文件中控制) 全局广播既可以动态注册,也可以静态注册。
3、注意:
- 本地广播无法通过静态注册来接收,相比起系统全局广播更加高效
- 在广播中启动activity的话,需要为intent加入FLAG_ACTIVITY_NEW_TASK的标记,不然会报错,因为需要一个栈来存放新打开的activity。
- 广播中弹出AlertDialog的话,需要设置对话框的类型为:TYPE_SYSTEM_ALERT不然是无法弹出的。
二、本地广播的使用
发送本地广播:LocalBroadcastManager.getInstance(BroadcastActivity.this).sendBroadcast(new Intent("com.hbbfxy.localbroadcast"));
注册本地广播:LocalBroadcastManager.getInstance(this).registerReceiver(localBroadcast, intentFilter);
解注册本地广播:LocalBroadcastManager.getInstance(this).unregisterReceiver(localBroadcast);//接触注册广播
三、本地广播的实现原理
我们通过本地广播的基本使用知道本地广播和全局广播在形式上主要的不同源于LocalBroadcastManager这个类。所以要想了解本地广播的实现原理,看这个类就可以。
接下来我们通过主要方法了解内部实现。
1、LocalBroadcastManager.getInstance(this) //实例化本地广播管理者
/*单例模式,进程中维持一份数据*/
public static LocalBroadcastManager getInstance(Context context) {
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
private LocalBroadcastManager(Context context) {
mAppContext = context;
//通过主线程的Looper构造的Handler
mHandler = new Handler(context.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_EXEC_PENDING_BROADCASTS:
executePendingBroadcasts();
break;
default:
super.handleMessage(msg);
}
}
};
}
在了解其他方法前,我们先来了解一下LocalBroadcastManager类的两个内部数据类(ReceiverRecord 和 BroadcastRecord )和三个数据集合。
private static final class ReceiverRecord {
//记录当前意图过滤
final IntentFilter filter;
//记录当前广播接收器
final BroadcastReceiver receiver;
//是否正在广播
boolean broadcasting;
//是否挂掉
boolean dead;
ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) {
filter = _filter;
receiver = _receiver;
}
}
private static final class BroadcastRecord {
//记录当前意图
final Intent intent;
//记录符合当前意图的ReceivedRecord数据结构
final ArrayList<ReceiverRecord> receivers;
BroadcastRecord(Intent _intent, ArrayList<ReceiverRecord> _receivers) {
intent = _intent;
receivers = _receivers;
}
}
//记录当前注册所有广播
private final HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>> mReceivers= new HashMap<>();
//记录当前拥有某Action的广播
private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();
//记录当前等待执行的广播
private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<>();
2、 LocalBroadcastManager.getInstance(this)
.registerReceiver(localBroadcast, intentFilter); // 注册广播
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
synchronized (mReceivers) {
/*将广播接收者和对应的意图过滤匹配起来,注意:一个广播接受者可能有多个意图过滤。*/
ReceiverRecord entry = new ReceiverRecord(filter, receiver);
ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
if (filters == null) {
filters = new ArrayList<>(1);
mReceivers.put(receiver, filters);
}
filters.add(entry);
//将意图过滤中的Action和对应得广播接受者对应起来,注意:一个Action可能对应多个广播接受者
for (int i=0; i<filter.countActions(); i++) {
String action = filter.getAction(i);
ArrayList<ReceiverRecord> entries = mActions.get(action);
if (entries == null) {
entries = new ArrayList<ReceiverRecord>(1);
mActions.put(action, entries);
}
entries.add(entry);
}
}
}
3、LocalBroadcastManager.getInstance(this)
.unregisterReceiver(localBroadcast);//解除注册本地广播
public void unregisterReceiver(BroadcastReceiver receiver) {
synchronized (mReceivers) {
//删除指定广播,并返回指定广播对应的所有意图过滤。
final ArrayList<ReceiverRecord> filters = mReceivers.remove(receiver);
if (filters == null) {
return;
}
/*遍历指定广播的所有意图过滤*/
for (int i=filters.size()-1; i>=0; i--) {
final ReceiverRecord filter = filters.get(i);
//标记当前广播挂掉
filter.dead = true;
/*遍历过滤意图的所有Action*/
for (int j=0; j<filter.filter.countActions(); j++) {
final String action = filter.filter.getAction(j);
/*根据Action遍历mAction列表*/
final ArrayList<ReceiverRecord> receivers = mActions.get(action);
if (receivers != null) {
for (int k=receivers.size()-1; k>=0; k--) {
final ReceiverRecord rec = receivers.get(k);
/*mAction列表中如果有指定广播要删除,并标记mAction列表中的该广播挂掉*/
if (rec.receiver == receiver) {
rec.dead = true;
receivers.remove(k);
}
}
if (receivers.size() <= 0) {
mActions.remove(action);
}
}
}
}
}
}
4、LocalBroadcastManager.getInstance(BroadcastActivity.this)
.sendBroadcast(new Intent(“com.hbbfxy.localbroadcast”));//发送广播
public boolean sendBroadcast(Intent intent) {
synchronized (mReceivers) {
/*获取意图中的过滤信息*/
final String action = intent.getAction(); //行为 Action
final String type = intent.resolveTypeIfNeeded( //类型 Type
mAppContext.getContentResolver());
final Uri data = intent.getData(); //URI
final String scheme = intent.getScheme(); //scheme
final Set<String> categories = intent.getCategories(); // 种类
//根据意图中的Action获取mAction列表中所有的广播接收者
ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
if (entries != null) {
//保存符合意图的广播接收者
ArrayList<ReceiverRecord> receivers = null;
/*遍历广播接受者*/
for (int i=0; i<entries.size(); i++) {
ReceiverRecord receiver = entries.get(i);
/*判断该广播是否正在广播,如果是则放弃本次广播*/
if (receiver.broadcasting) {
continue;
}
/*判断该广播接受者是否符合意图*/
int match = receiver.filter.match(action, type, scheme, data,
categories, "LocalBroadcastManager");
if (match >= 0) {
if (receivers == null) {
receivers = new ArrayList<ReceiverRecord>();
}
/*如果该广播接收者符合意图,则保存并标记正在广播*/
receivers.add(receiver);
receiver.broadcasting = true;
} else {
}
}
/*遍历符合意图的广播接收者,将标记为设置为广播结束*/
if (receivers != null) {
for (int i=0; i<receivers.size(); i++) {
receivers.get(i).broadcasting = false;
}
/*将符合意图的广播接受者和意图通过BroadcastRecord类对应起来,然后通过Handle发送*/
mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
}
return true;
}
}
}
return false;
}
最后通过在构造方法中构建的主线程Handler发送消息 执行executePendingBroadcasts()该方法
/*执行等待的广播发送*/
private void executePendingBroadcasts() {
for (int j=0; j<nbr; j++) {
final ReceiverRecord rec = br.receivers.get(j);
if (!rec.dead) {
rec.receiver.onReceive(mAppContext, br.intent);
}
}
}
通过上面对源码的分析我们知道本地广播的实现原理其实就是 利用HashMap和List来维护广播接收者、IntentFileter、Intent三者之间的关系。