目录
- LocalBroadcastManager简介
- LocalBroadcastManager使用
- 源码解析
- 总结
1. LocalBroadcastManager简介
前面的文章介绍了常用的Broadcast原理,这种广播是经过系统调度的,不论是动态注册还是静态注册,不论是有序广播还是无序广播,都要经过ams,好处很显然,可以实现跨进程之间的通信,而且有很多广播本身就是由系统发出的,我们需要在APP的进程中监听,但是也是有坏处的,因为AMS其实是很繁忙的,如果出现比较特殊的情况导致AMS被阻塞,就可能会影响我们自身收到receiver的时间,甚至收不到,这样就可能会影响到APP自身的业务。
Android中也是考虑到了这种情况,因此在v4包中引入了LocalBroadcastManager,顾名思义,叫做本地广播,也就是只在APP的自身进程中运行,不会被其他情况干扰,当然这个不能用作跨进程通信的手段。
2. LocalBroadcastManager使用
核心类就是LocalBroadcastManager,这个类的方法并不多,但是也涵盖了常用的registerReceiver,unregisterReceiver,sendBroadcast
等方法。
先来看看其中主要都有那些方法:
单例模式获取LocalBroadcastManager
public static LocalBroadcastManager getInstance(Context context);
广播注册
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter);
取消注册
public void unregisterReceiver(BroadcastReceiver receiver);
发送广播
public boolean sendBroadcast(Intent intent);
同步发送广播
public void sendBroadcastSync(Intent intent);
执行广播派发
private void executePendingBroadcasts();
可以看到,和平时使用的广播没有太大区别,不过需要通过getInstance获取一个单例之后操作,其中有一个方法看起来没有见过,executePendingBroadcasts
,而且是一个private方法,接下来从源码看一下这个LocalBroadcast的实现。
3. 源码解析
3.1 getInstance
private static LocalBroadcastManager mInstance;
public static LocalBroadcastManager getInstance(Context context) {
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
通过ApplicationContext创建单例。
3.2 registerReceiver
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
// mReceivers是一个hashmap
// key是BroadcastReceiver,value是receiverRecord的list
synchronized (mReceivers) {
// 根据filter和receiver创建ReceiverRecord
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);
for (int i=0; i<filter.countActions(); i++) {
String action = filter.getAction(i);
// mActions同样是一个hashmap
// key是广播action,value是ReceiverRecord的list
ArrayList<ReceiverRecord> entries = mActions.get(action);
if (entries == null) {
entries = new ArrayList<ReceiverRecord>(1);
mActions.put(action, entries);
}
entries.add(entry);
}
}
}
ReceiverRecord中就只存了broadcastReceiver以及intentFilter
这段逻辑并不复杂,主要实现以下三步:
- 根据receiver和filter创建ReceiverRecord
- 将上面创建的record放入到mReceivers的value的list中
- 对本次广播的filter中所有action,在mAction的value中分别放入ReceiverRecord对象
经过注册最终的结果是这样:
mReceivers中存放的是已注册的receiver以及其对应的ReceiverRecord,同一个receiver如果多次用相同的filter不会生效多次,但是如果filter不同注册多次,那么就会在mReceivers存储多个ReceiverRecord;
mAction中存放的是已注册的所有action,以及这个action对应的ReceiverRecord,如果这个filter中有多个action,那么就会存储多个相同的ReceiverRecord。
3.3 unregisterReceiver
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;
for (int j=0; j<filter.filter.countActions(); j++) {
final String action = filter.filter.getAction(j);
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);
if (rec.receiver == receiver) {
rec.dead = true;
receivers.remove(k);
}
}
if (receivers.size() <= 0) {
mActions.remove(action);
}
}
}
}
}
}
- 取消注册的时候,因为mReceivers的key是receiver,直接把value移除即可。
- 从移除的value(ReceiverRecord)的list中遍历,分别拿出其中的filter中的action,前面两步主要是为了拿到本次取消注册的所有action,拿到action后,遍历所有的action,根据action去mActions拿到这个action对应的所有的ReceiverRecord对象列表,把这个列表中的receiver和要移除的receiver相等的ReceiverRecord移除。
3.4 sendBroadcast
public boolean sendBroadcast(Intent intent) {
synchronized (mReceivers) {
final String action = intent.getAction();
// 根据指定的schema获取intent的type
final String type = intent.resolveTypeIfNeeded(
mAppContext.getContentResolver());
// 获取uri
final Uri data = intent.getData();
final String scheme = intent.getScheme();
final Set<String> categories = intent.getCategories();
// 根据action,拿到所有注册了监听这个action的ReceiverRecord
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);
// 因为不同的action中,可能有相同的ReceiverRecord,需要判断状态
// 如果正在发送了就下一个
if (receiver.broadcasting) {
continue;
}
// 根据ReceiverRecord中的record匹配
// 匹配成功之后,就加入到要派发的列表中
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;
}
}
// 到这里就找到了所有的监听这个action的receiver
if (receivers != null) {
for (int i=0; i<receivers.size(); i++) {
receivers.get(i).broadcasting = false;
}
// 把要派发的广播加入到mPendingBroadcasts中
mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
// 发送message
if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
}
return true;
}
}
}
return false;
}
收集需要派发的receiver,并post消息到主线程
3.5 handleMessage
private LocalBroadcastManager(Context context) {
mAppContext = context;
// 可以看到这里用的是主线程的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);
}
}
};
}
这里走到了前面我们提到的那个private方法,看来这个方法是派发的核心了。
3.6 executePendingBroadcasts
private void executePendingBroadcasts() {
// 死循环,直到广播都派发完毕才return
while (true) {
final BroadcastRecord[] brs;
synchronized (mReceivers) {
final int N = mPendingBroadcasts.size();
// 没有需要派发的广播那就return了
if (N <= 0) {
return;
}
brs = new BroadcastRecord[N];
mPendingBroadcasts.toArray(brs);
mPendingBroadcasts.clear();
}
// 便利了所有的receiver之后,回调了receiver的onReceive
// mAppContext正是创建单例时的context
for (int i=0; i<brs.length; i++) {
final BroadcastRecord br = brs[i];
final int nbr = br.receivers.size();
for (int j=0; j<nbr; j++) {
final ReceiverRecord rec = br.receivers.get(j);
if (!rec.dead) {
rec.receiver.onReceive(mAppContext, br.intent);
}
}
}
}
}
果然,真正的广播派发以及receiver的回调就在这里。
前面有提到还有一个方法sendBroadcastSync
3.7 sendBroadcastSync
public void sendBroadcastSync(Intent intent) {
if (sendBroadcast(intent)) {
executePendingBroadcasts();
}
}
从名字上看意思应该是同步发送广播,事实上正是这样,在调用了sendBroadcast之后,其中是经过了向主线程post消息,然后主线程去处理receiver的,而这里sendBroadcast返回值为true就代表收集到了receiver,直接在当前线程开始调度了。因为在executePendingBroadcasts方法中是持锁派发,而且有对需要派发广播的数量校验,因此并不需要担心广播会被派发多次。
总结
- 依旧是经典的观察者模式
- 注册的时候通过mReceivers/mActions两个map从不同的维度保存了已注册的receiver
- 发送广播之后根据action以及filter的匹配,查找需要派发的receiver
- 正常流程是post消息到主线程派发
- 可以选择在当前线程同步进行广播派发