思考
为什么需要两个map呢?
private final HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>> mReceiver = new HashMap<>();
private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();
复制代码
- 注册广播的时候,根据receiver对象和action值(注意是action值,不是IntentFilter)分别进行了归类,存在了上述两个集合中。
- 发送广播的时候,先根据action值找出了所有对应的ReceiverRecord,然后再拿出ReceiverRecord存储的IntentFilter和Intent进行匹配,匹配上的取出其中的receiver,这个流程首先说明了mActions的存在意义,
- 那mReceiver的存在意义又是啥呢?感觉很多余啊啊啊啊啊啊啊啊啊啊啊啊啊,这是我们只考虑了注册和发送广播,还有取消注册呢。
- 没有mReceiver这个集合,根据mActions怎么取消呢,那就只能全量遍历mActions,遍历这个HashMap来一个个取出对应的集合,再遍历集合找出匹配的receiver并remove掉,这可是个全量的活啊,造孽啊。如果有mReceiver这个集合,则可以缩小检索范围,先mReceiver根据receiver这个key移除掉value,然后再根据这个receiver对应的ArrayList遍历出涉及到的action,再把mActions中action作为key对应的集合中涉及到此receiver的ReceiverRecord给remove掉,如果操作完之后,对应的集合为空了,则说明没有关于这个action的观察者了,可以从mActions中彻底移除了。
- 同样的道理如果只用mReceiver而不用mActions,那么发送广播时就得全量遍历。
- 可见,mReceiver是为了方便取消注册时检索,而mActions是为了方便发送广播时检索。这也是Map相对于List在检索上的优势体现。
扩展思考
为什么获取单列时使用的锁是mLock,而其他方法使用的锁是mReceivers???
答:其他方法基本都涉及到对mReceivers的读写改查,因此需要使用同一把锁,形成互斥,但是获取单列和这些方法并不存在数据的交集,因此不需要互斥,所以使用不同的锁。此处和锁定类的效果是一样的。
推荐阅读:Java中Synchronized的用法
获取单列
传入context
,调用getApplicationContext
,最终持有的是Application实例
private static final Object mLock = new Object();
private static LocalBroadcastManager mInstance;
@NonNull
public static LocalBroadcastManager getInstance(@NonNull Context context) {
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
复制代码
注册(锁mReceivers)
public void registerReceiver(@NonNull BroadcastReceiver receiver,
@NonNull IntentFilter filter) {
// 锁mReceivers
synchronized (mReceivers) {
ReceiverRecord entry = new ReceiverRecord(filter, receiver);
// mReceivers键为receiver,值为ReceiverRecord,一对多
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键为action,值为ReceiverRecord,一对多
ArrayList<ReceiverRecord> entries = mActions.get(action);
if (entries == null) {
entries = new ArrayList<ReceiverRecord>(1);
mActions.put(action, entries);
}
entries.add(entry);
}
}
}
复制代码
取消注册(锁mReceivers)
public void unregisterReceiver(@NonNull BroadcastReceiver receiver) {
// 锁mReceivers
synchronized (mReceivers) {
// mReceivers是HashMap,移除掉receiver对应的ReceiverRecord集合
final ArrayList<ReceiverRecord> filters = mReceivers.remove(receiver);
if (filters == null) {
return;
}
// 根据receiver对应的ReceiverRecord集合
for (int i=filters.size()-1; i>=0; i--) {
final ReceiverRecord filter = filters.get(i);
filter.dead = true;
// 遍历取出来每个IntentFilter中的action(多个)
for (int j=0; j<filter.filter.countActions(); j++) {
final String action = filter.filter.getAction(j);
// 取出每个action对应的ReceiverRecord集合
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);
// 如果ReceiverRecord中的receiver是取消注册的receiver,则从集合中移除
// 此处remove时,需要倒序遍历,源码很值得学习啊
if (rec.receiver == receiver) {
rec.dead = true;
receivers.remove(k);
}
}
// 如果receivers的长度为0了,说明没有关于这个action的观察者了,可以从mActions中彻底移除了
if (receivers.size() <= 0) {
mActions.remove(action);
}
}
}
}
}
}
复制代码
发送广播(锁mReceivers)
// 精简代码
public boolean sendBroadcast(@NonNull Intent intent) {
// 锁mReceivers
synchronized (mReceivers) {
final String action = intent.getAction();
final String type = intent.resolveTypeIfNeeded(
mAppContext.getContentResolver());
final Uri data = intent.getData();
final String scheme = intent.getScheme();
final Set<String> categories = intent.getCategories();
// action对应的ReceiverRecord,其实存储的是注册的receiver
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) {
// 相同的则不必再加入
// 为什么此处要增加这个判断呢???????????????
// 因为从注册的源码来看,如果我们重复调用了registerReceiver,
// 就会导致同一个receiver被重复加入mReceivers和mActions中,
// 这显然是需要避免的,因为这是粗心导致的,根本不存在同一个观察者需要被注册两次,尤其是IntentFilter还是一样的
continue;
}
// 根据IntentFilter判断是否有匹配的receiver
int match = receiver.filter.match(action, type, scheme, data,
categories, "LocalBroadcastManager");
if (match >= 0) {
if (receivers == null) {
// 有匹配的再初始化集合,源码严格遵循使用时再初始化,避免没有匹配时也初始化集合,浪费内存空间
receivers = new ArrayList<ReceiverRecord>();
}
// 有匹配的receiver,则加入集合中
receivers.add(receiver);
// 标记为已经加入,防止重复添加
receiver.broadcasting = true;
} else {
// 没有匹配的receiver,源码打印了一堆Log
}
}
if (receivers != null) {
for (int i=0; i<receivers.size(); i++) {
// 取消添加标记,重置状态,以便下次发送广播
receivers.get(i).broadcasting = false;
}
mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
}
return true;
}
}
}
return false;
}
复制代码
处理广播(锁mReceivers)
// 注意看,这个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);
}
}
};
// 处理广播
void executePendingBroadcasts() {
while (true) {
final BroadcastRecord[] brs;
// 锁mReceivers
synchronized (mReceivers) {
final int N = mPendingBroadcasts.size();
if (N <= 0) {
return;
}
brs = new BroadcastRecord[N];
mPendingBroadcasts.toArray(brs);
mPendingBroadcasts.clear();
}
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) {
// 调用我们的receiver的onReceive方法
// 看清楚了,这里时mAppContext啊,这个值可是context.getApplicationContext()
rec.receiver.onReceive(mAppContext, br.intent);
}
}
}
}
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END