概述
LocalBroadcastManager
作为Android
系统广播机制的一种高效方案,可以有效地保护数据的安全性和隐秘性,能够让数据只能在自身应用中传播,不同与系统广播比较复杂的实现机制,因此回顾下其使用方法和原理。
使用
//比如在Activity中使用
//创建IntentFilter,指定触发的action,可以指定多个action
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("test");
intentFilter.addAction("test2");
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d("接受",action);
if (intent.getAction().equals("test")){
Log.d("数据",intent.getStringExtra("test"));
}
}
};
//注册本地广播
LocalBroadcastManager.getInstance(context).registerReceiver(receiver,intentFilter);
然后发送广播:
Intent intent = new Intent();
intent.setAction("test");
intent.putExtra("test","测试数据");
intent.setData
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
控制台输出:
08-01 15:05:23.209 23618-23618/com.franky.testD/接受: test
08-01 15:05:23.209 23618-23618/com.franky.testD/数据: 测试数据
解除注册:
LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver);
总结起来就是:
1.创建IntentFilter
和BroadcastReceiver
对象,BroadcastReceiver
对象处理回调方法;
2.使用LocalBroadcastManager
注册IntentFilter
和BroadcastReceiver
;
3.创建Intent
对象,封装对应的action
,并可传递数据;
4.使用LocalBroadcastManager
发送广播;
3.不需要时候调用LocalBroadcastManager
解除注册;
原理
首先看看是如何获取LocalBroadcastManager
对象的:
@NonNull
public static LocalBroadcastManager getInstance(@NonNull Context context) {
synchronized (mLock) {
if (mInstance == null) {
//使用了ApplicationContext
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
就是很典型的一个单例模式,整个应用使用这一个LocalBroadcastManager
对象。
接下来看看注册:
//这个mReceivers对象保存了一个receiver对象可能对应的多个reveiver和IntentFilter的键值对
private final HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>> mReceivers
= new HashMap<>();
//这个mActions 对象保存了action可能对应的多个reveiver和IntentFilter的键值对
private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();
public void registerReceiver(@NonNull BroadcastReceiver receiver,
@NonNull IntentFilter filter) {
synchronized (mReceivers) {
//ReceiverRecord 就是封装了filter, receiver的一个包装对象
ReceiverRecord entry = new ReceiverRecord(filter, receiver);
//从mReceivers中取出对应的filters集合,因为有时候可能使用一个receiver对象
//和多个IntentFilter注册的情况,所以这里使用了mReceivers来保存这种可能情况
ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
if (filters == null) {//如果为空那么初始化filters
filters = new ArrayList<>(1);//默认容量为1,为了优化内存
mReceivers.put(receiver, filters);
}
filters.add(entry);//这里也把封装的entry放进去
//这里循环取出当前注册的filter的action
for (int i=0; i<filter.countActions(); i++) {
String action = filter.getAction(i);
//从mActions里通过action取出对应的ReceiverRecord集合,因为有时候可能
//使用一个action和多个不同reveiver对象注册
ArrayList<ReceiverRecord> entries = mActions.get(action);
if (entries == null) {//entries为空的话就初始化一个
entries = new ArrayList<ReceiverRecord>(1);
mActions.put(action, entries);//放入对应关系
}
//放入当前封装的ReceiverRecord对象
entries.add(entry);
}
}
}
注册过程主要是两个缓存对象:
mReceivers
负责保存一个receiver
对应多IntentFilter
的情况;mActions
负责保存一个action
对应多receiver
的情况;
分析完了注册,看看发送方法的实现:
//mPendingBroadcasts 就是保存了待发送的intent和receiver的集合
private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<>();
//如果广播被一个或者多个receiver接收到了,那么就返回true
public boolean sendBroadcast(@NonNull Intent intent) {
synchronized (mReceivers) {
//获取intent的action及其他信息
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();
final boolean debug = DEBUG ||
((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
if (debug) Log.v(
TAG, "Resolving type " + type + " scheme " + scheme
+ " of intent " + intent);
//这里通过action获取注册时候mAcitons保存的reveiver集合
ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
if (entries != null) {//只有不为空才能进行发送
if (debug) Log.v(TAG, "Action list: " + entries);
//这里准备一个成功匹配的receivers集合
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);
//如果这个reveiver正在发送中,那么跳过
if (receiver.broadcasting) {
if (debug) {
Log.v(TAG, " Filter's target already added");
}
continue;
}
//注册的filter是否去传递的intent的各项信息匹配
int match = receiver.filter.match(action, type, scheme, data,
categories, "LocalBroadcastManager");
if (match >= 0) {//大于0就是匹配成功
if (debug) Log.v(TAG, " Filter matched! match=0x" +
Integer.toHexString(match));
if (receivers == null) {
receivers = new ArrayList<ReceiverRecord>();
}
//这里把匹配成功的reveiver放入集合
receivers.add(receiver);
//更改发送标识为true
receiver.broadcasting = true;
} else {
if (debug) {
String reason;
switch (match) {
case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
default: reason = "unknown reason"; break;
}
Log.v(TAG, " Filter did not match: " + reason);
}
}
}
if (receivers != null) {//不为空说明有匹配成功,进行发送
for (int i=0; i<receivers.size(); i++) {
//将发送标识变成false
receivers.get(i).broadcasting = false;
}
//重新包装成BroadcastRecord,加入到mPendingBroadcasts集合中
mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
//这里出现了mHandler,说明消息是通过handler发出的,这里通过判断如果正在发送,就直接返回true了
if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
//如果没有发送,那么就发送一个标识,开始进入handler的消息处理机制
mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
}
return true;
}
}
}
return false;
}
发送方法主要就是提取出符合当前Intent
对象的注册的receiver
集合,最后利用Handler
消息机制来处理,这个过程也不复杂。
那么看看mHandler
的实现:
//其实在构造LocalBroadcastManager时,mHandler就初始化了
private LocalBroadcastManager(Context context) {
mAppContext = context;
//这里传入了主线程的Looper
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);
}
}
};
}
mHandler
的处理非常简单,最终会执行到这个executePendingBroadcasts()
方法:
private void executePendingBroadcasts() {
while (true) {
final BroadcastRecord[] brs;
synchronized (mReceivers) {
//判断下这个集合的大小,大小为0,就return,结束循环
final int N = mPendingBroadcasts.size();
if (N <= 0) {
return;
}
//复制到数组
brs = new BroadcastRecord[N];
mPendingBroadcasts.toArray(brs);
//清空集合,释放内存
mPendingBroadcasts.clear();
}
//双循环取出receiver
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的回调
rec.receiver.onReceive(mAppContext, br.intent);
}
}
}
}
}
处理逻辑也很简单,现将mPendingBroadcasts
复制到一个临时数组,然后循环取出receiver
,如果没有反注册,那么进行回调,发送完毕。
另外LocalBroadcastManager
还提供了同步的发送方法:
public void sendBroadcastSync(@NonNull Intent intent) {
//这里在mHandler处理之前就返回true了
if (sendBroadcast(intent)) {
//由于executePendingBroadcasts方法是在当前线程,所以会阻塞当前线程
executePendingBroadcasts();
}
}
最后来看看反注册的实现:
public void unregisterReceiver(@NonNull BroadcastReceiver receiver) {
synchronized (mReceivers) {
//使用remove方法取出reveiver对应的filters集合
final ArrayList<ReceiverRecord> filters = mReceivers.remove(receiver);
if (filters == null) {//没有就直接reture
return;
}
//开始循环删除
for (int i=filters.size()-1; i>=0; i--) {
final ReceiverRecord filter = filters.get(i);
filter.dead = true;//将标识设为true
//循环该filter的action
for (int j=0; j<filter.filter.countActions(); j++) {
final String action = filter.filter.getAction(j);
//根据action取出对应的receivers
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);
//判断缓存的reveiver和传入的receive是否是一个对象
//如果是一个对象,改变标识为true,并从集合中移除
if (rec.receiver == receiver) {
rec.dead = true;
receivers.remove(k);
}
}
//如果receivers没有对象了,说明这个action没有receiver接受了
//那么从mActions集合中移除这个action
if (receivers.size() <= 0) {
mActions.remove(action);
}
}
}
}
}
}
反注册的流程总结下:
- 首先移除
receiver
对应的filters
集合; - 从这个
filters
集合中循环所有的action
; - 从
mActions
集合中取出对应action
的receivers
集合; - 从
receivers
集合中移除和反注册receiver
对象相同的ReceiverRecord 对象 - 如果对应的
receivers
没有任何receiver
了,那么从mActions
集合中移除整个action
总结
LocalBroadcastManager
只能动态注册广播;- 在不需要的时候尽量早的反注册
receiver
; LocalBroadcastManager
只能在单进程应用内使用,无法进行跨进程通信;