LocalBroadcast是一个应用内的局部广播,广播范围只限于应用内部,并且不属于四大组件,相对高效很多,可以用来实现事件总线,相比其他事件总线实现方案,先对简单,高效。
而且,其实现很简单,设计的很好;
优点
- 广播范围只限于应用内部,不会出现数据泄漏和安全漏洞问题;
- 相对于系统广播,更加高效便捷;
- 相对于其他事件总线框架,实现简单,高效,不存在例如EventBus事件类代码区域划分问题;
- 可以集中管理Action,使用系统Intent传递数据,学习成本低;
- 虽然Intent传递数据,但是内部没有涉及到序列化,所以不同于四大组件的Intent实体需要实现序列化,并且大小也无限制;
- 使用IntentFilter进行事件匹配,所以可以是多维度的,是根据Action, Type, Scheme, Uri, Categories进行匹配的;
缺点
- 无法线程变换,事件处理默认在主线程;
- 无法实现粘性事件;
- 如果不定义Action常量,则需要用文档管理维护大量的Action;IntentFilter也相当于事件类,如果是多纬度的,那么就需要维护IntentFilter这个事件类了;
- 查找订阅事件或者发送事件比较困难,只能全局搜索,如果定义Action常量,那么Action代码也会出现区域划分问题;
注意
- 可以重复注册,并且重复注册后会收到多次回调;
使用
//1. 创建BroadcastReceiver
val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.i("shuxin.wei", "onReceive")
}
}
//2. 在合适的位置注册监听
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter("ACTION_TEST"))
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter("ACTION_TEST"))
//3. 发布事件
LocalBroadcastManager.getInstance(this).sendBroadcastSync(Intent("ACTION_TEST"))
Log.i("shuxin.wei", "sendBroadcastSync")
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent("ACTION_TEST"))
Log.i("shuxin.wei", "sendBroadcast")
//4. 在合适的位置取消监听
if (broadcastReceiver != null) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
}
//日志输出
//可以看到同步广播是在onReceive执行完,才继续向下执行的;
//广播是可以重复注册的,并会重复收到;
shuxin.wei: onReceive
shuxin.wei: onReceive
shuxin.wei: sendBroadcastSync
shuxin.wei: sendBroadcast
shuxin.wei: onReceive
shuxin.wei: onReceive
源码分析
1. 数据结构
//保存接收者与IntentFilter,并记录广播状态
//这个实体,既可以用作代替BroadcastReceiver,也可以用作代替IntentFilter
//在注册时利用其保存了BroadcastReceiver与多个IntentFilter对应关系
//也利用其保存了Action与多个BroadcastReceiver的对应关系
private static final class ReceiverRecord {
final IntentFilter filter;
final BroadcastReceiver receiver;
boolean broadcasting;
boolean dead;
ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) {
filter = _filter;
receiver = _receiver;
}
}
//保存广播和Intent,在分发广播时,将Intent传递到接收者的receiver方法中
//receiver.onReceive(mAppContext, br.intent)
private static final class BroadcastRecord {
final Intent intent;
final ArrayList<ReceiverRecord> receivers;
BroadcastRecord(Intent _intent, ArrayList<ReceiverRecord> _receivers) {
intent = _intent;
receivers = _receivers;
}
}
//记录BroadcastReceiver和注册的所有IntentFilter
//例如在多个位置对相同的BroadcastReceiver注册多个IntentFilter
HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>> mReceivers = new HashMap<>();
//记录Action和对应所有的BroadcastReceiver
//不同的BroadcastReceiver可以注册相同的Action
HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();
//记录所有要分发的Intent和对应的所有的BroadcastReceiver
//不同BroadcastReceiver可以对应相同的Action,所以,分发时一个Intent可以对应多个BroadcastReceiver
ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<>();
2. 创建LocalBroadcastManager实例
- LocalBroadcastManager是相对线程安全的单例;
- 使用ApplicationContext,不会出现内存泄漏;
- Handler使用MainLooper,回调只能在主线程;
public static LocalBroadcastManager getInstance(Context context) {
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
private LocalBroadcastManager(Context context) {
mAppContext = context;
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);
}
}
};
}
2. 注册监听
- 同步方法,线程安全
- 用ReceiverRecord保存BroadcastReceiver和IntentFilter
- 从HashMap中获取BroadcastReceiver对应的IntentFilter集合
- 如果没有注册过BroadcastReceiver,则创建新的filters集合,添加到HashMap中,并将ReceiverRecord保存到filters集合;
- 开始处理Action,遍历要注册的IntentFilter的Action;
- 根据Action从HashMap中取到对应的BroadcastReceiver集合;
- 如果没有注册这个Action,则创建新的BroadcastReceiver集合,添加到HashMap中,并将ReceiverRecord保存到BroadcastReceiver集合;
总结:同一个BroadcastReceiver可以注册多个相同或不同IntentFilter;
相同Action可以对应多个相同或不同BroadcastReceiver;
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);
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. 取消注册
- 同步方法,线程安全;
- 根据BroadcastReceiver移除对应的所有的IntentFilter;
- 如果IntentFilter集合为空,那么说明已经被unregister过,Action的移除也处理过了,直接结束;
- 如果IntentFilter集合不为空,则还需要处理Action,遍历所有的IntentFilter;
- 标记ReceiverRecord为dead;继续遍历IntentFilter中的Action;
- 根据Action取出对应的ReceiverRecord集合,遍历ReceiverRecord集合,移除匹配的BroadcastReceiver;
- 如果Action取出对应的ReceiverRecord集合为空了,那么不再需要这个Action,移除掉,释放内存;
思考:如果mActions里面用HashMap<String,HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>>>保存Action与ReceiverRecord对应关系,那么移除时,可以直接根据BroadcastReceiver移除ReceiverRecord,理论上效率应该会更高一些,虽然性能差距可能不大
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);
}
}
}
}
}
}
4. 发送广播
- 相对主线程,可以是异步发送的,加了锁,线程安全;
- 解析Intent,根据Action取出所有对应的ReceiverRecord;
- 如果ReceiverRecord集合不为空,则进行事件处理,否则,没有对应的事件,直接retrun false;
- 遍历ReceiverRecord集合,判断当前事件是否已经添加到等待处理的广播集合中;
broadcasting的作用是??????在注册时ReceiverRecord都是直接new出来的,所以不会出现重复,那么broadcasting的作用是什么呢?没搞懂!!! - 进行IntentFilter匹配,匹配成功,添加到待分发的ReceiverRecord集合中;
- 将Intent和ReceiverRecord集合包装添加到待分发的mPendingBroadcasts中;
- 如果mHandler里没有等待执行的任务,则启动一个任务;
- 任务启动后会回调到mHandler中,执行executePendingBroadcasts()方法;
- 将mPendingBroadcasts复制一份,然后调用receiver.onReceive(mAppContext, br.intent),清空mPendingBroadcasts,完成事件分发;
分发中的死循环是处理异步任务可能随时见添加新的事件,确保一次执行能将所有任务处理完;
public boolean sendBroadcast(Intent intent) {
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();
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 (debug) Log.v(TAG, "Matching against filter " + receiver.filter);
if (receiver.broadcasting) {
if (debug) {
Log.v(TAG, " Filter's target already added");
}
continue;
}
int match = receiver.filter.match(action, type, scheme, data,
categories, "LocalBroadcastManager");
if (match >= 0) {
if (debug) Log.v(TAG, " Filter matched! match=0x" +
Integer.toHexString(match));
if (receivers == null) {
receivers = new ArrayList<ReceiverRecord>();
}
receivers.add(receiver);
receiver.broadcasting = true;
}
}
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;
}
private void executePendingBroadcasts() {
while (true) {
final BroadcastRecord[] brs;
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) {
rec.receiver.onReceive(mAppContext, br.intent);
}
}
}
}
}
同步广播
sendBroadcast方法是同步的,一定是执行完了receiver.onReceive(mAppContext, br.intent)回调才会继续向下执行,否则阻塞于while循环中;
public void sendBroadcastSync(Intent intent) {
if (sendBroadcast(intent)) {
executePendingBroadcasts();
}
}