本地广播机制
Android广播机制分为本地广播和全局广播。本地广播仅在自身应用内传播,全局广播则在整个系统所有应用内传播。
本地广播的优点
- 传播的数据不会离开自身应用,因此本地广播不需要担心私密数据泄露;
- 其他应用发送相同广播不会被自身应用监听到,因此本地广播不需要担心安全漏洞风险;
- 发送本地广播比全局广播效率更高;
源码解析
LocalBroadcastManager是系统提供的本地广播管理类,协助进行本地广播的注册与发送。
ReceiverRecord是对Filter和Receiver的封装类;BroadcastRecord是对Intent和ReceiverRecord的封装类。private static final class ReceiverRecord { final IntentFilter filter; final BroadcastReceiver receiver; boolean broadcasting; // 是否正在广播中; boolean dead; // 是否已解注册 } private static final class BroadcastRecord { final Intent intent; final ArrayList<ReceiverRecord> receivers; }- 内部持有mReceivers和mActions两个映射表,分别表示监听器对应的多个Record、Action对应的多个Record;还存在mPendingBroadcasts集合存储
BroadcastRecord,表示需要执行的广播;private final HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>> mReceivers = new HashMap<>(); private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>(); private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<>(); registerReceiver()注册时,首先新建ReceiverRecord,添加到mReceivers中;然后遍历Filter的Actions,在对应的mActions中添加。public void registerReceiver(@NonNull BroadcastReceiver receiver, @NonNull IntentFilter filter) { synchronized (mReceivers) { ReceiverRecord entry = new ReceiverRecord(filter, receiver); /** 同一个Receiver可以多次注册 */ ArrayList<ReceiverRecord> filters = mReceivers.get(receiver); if (filters == null) { filters = new ArrayList<>(1); mReceivers.put(receiver, filters); } filters.add(entry); /** 遍历filter中的所有Action,获取监听Action的接收器列表,添加新的Record到列表中 */ 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); } } }unregisterReceiver()解注册时,根据Receiver首先查到所有ReceiverRecord,然后遍历获取Actions,然后在mActions中删除对应的Record。public void unregisterReceiver(@NonNull BroadcastReceiver receiver) { synchronized (mReceivers) { /** 移除receiver在集合中对应的Record */ final ArrayList<ReceiverRecord> filters = mReceivers.remove(receiver); if (filters == null) { return; } /** 遍历Record,通过filter再遍历actions,移除receiver在mActions集合中的记录,设置Record#dead=true */ 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); } } } } } }sendBroadcast()发送广播- 首先解构Intent,然后根据Action获取到对应的
List<ReceiverRecord>; - 遍历此集合,判断Receiver是否匹配此Intent,若是则添加到receivers临时集合中,表示要接收此Intent的Receiver;
- 将receivers临时集合与Intent一起封装为
BroadcastRecord对象,发送消息使内部的Handler进行处理; - 遍历receivers,对仍处于监听状态的Receiver回调
onReceive()方法。 - 同一时刻只能存在一条
MSG_EXEC_PENDING_BROADCASTS信息,而对应的执行方法会将周期内所有广播全部执行。
public boolean sendBroadcast(@NonNull Intent intent) { synchronized (mReceivers) { /** 解构Intent */ 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(); /** 根据Intent#Action获取Record */ 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 { /** Intent与Receiver注册的Filter不匹配*/ } } /** 将上面得到的,需要响应的Record集合与Intent一起封装为BroadcastRecord,发送同步消息等待后续执行广播回调 */ 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; }- 首先解构Intent,然后根据Action获取到对应的
sendBroadcastSync()是同步阻塞的发送广播,在调用后立即执行广播接收者回调,而不会通过Handler进行消息排队。- 对于
dead和broadcasting两个flag的思考- 对于同一个Receiver和同一个IntentFilter,可以多次调用
registerReceiver()注册,因此mReceivers和mActions对应的集合中都有可能存在完全相同的ReceiverRecord。 - 注册解注册、发送广播、执行等方法都使用
synchronized进行线程管控,因此可以判断这两个flag没有实际用途。
- 对于同一个Receiver和同一个IntentFilter,可以多次调用
总结
本地广播不属于跨进程通信范畴,因此没有使用到如Binder等底层IPC机制,而仅仅是依靠全局变量、主线程的Handler以及线程同步机制实现的应用内消息传播。以此而言,效率比全局广播的跨进程通信更高,更适用于应用内跨组件通信的场景。