关于LocalBroadcastManager,首先要从BroadcastReceiver 说起,一次无意间打开BroadcastReceiver 源码,最上面的说明里面会有这么一段话:
If you don’t need to send broadcasts across applications, consider using this class with LocalBroadcastManager instead of the more general facilities described below. This will give you a much more efficient implementation (no cross-process communication needed) and allow you to avoid thinking about any security issues related to other applications being able to receive or send your broadcasts.
(⊙o⊙)…,LocalBroadcastManager是什么东东?从上述说明里面可知道,如果不需要跨进程通信,可以考虑LocalBroadcastManager替代BroadcastReceiver,这样会更高效更安全的实现广播。
行了,现在简单的知道了LocalBroadcastManager是什么玩意了,单从功能上通俗点说,可以理解为阉割版的BroadcastReceiver(本质上不是,最后会叙述本质区别),在BroadcastReceiver 设计之初是从全局考虑的,可以方便应用程序和系统、应用程序之间、应用程序内的通信,但是这样的设计会有一些问题,有一些软件就是通过拦截系统启动广播去操作自己的应用程序,比如android.intent.action.BOOT_COMPLETED。
现在我们把重心放到LocalBroadcastManager,首先先看一下源码中对LocalBroadcastManager的说明:
Helper to register for and send broadcasts of Intents to local objects within your process. This is has a number of advantages over sending global broadcasts with sendBroadcast(Intent):
- You know that the data you are broadcasting won’t leave your app, so don’t need to worry about leaking private data.
- It is not possible for other applications to send these broadcasts to your app, so you don’t need to worry about having security holes they can exploit.
- It is more efficient than sending a global broadcast through the system.
通过上述可知,LocalBroadcastManager 对比BroadcastReceiver 的三个优点:
- 发送的广播只会在当前APP中传播,不会泄露给其它APP,确保了数据传输的安全。
- 其它APP的广播无法发送到本APP中,不用担心安全漏洞被其它APP所利用。
- 比系统全局广播更加高效。
先看下LocalBroadcastManager 的完整源码,如下:
package android.support.v4.content;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
public class LocalBroadcastManager
{
private static final String TAG = "LocalBroadcastManager";
private static final boolean DEBUG = false;
private final Context mAppContext;
private final HashMap<BroadcastReceiver, ArrayList<IntentFilter>> mReceivers = new HashMap();
private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap();
private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList();
static final int MSG_EXEC_PENDING_BROADCASTS = 1;
private final Handler mHandler;
private static final Object mLock = new Object();
private static LocalBroadcastManager mInstance;
public static LocalBroadcastManager getInstance(Context context)
{
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
private LocalBroadcastManager(Context context) {
this.mAppContext = context;
this.mHandler = new Handler(context.getMainLooper())
{
public void handleMessage(Message msg)
{
switch (msg.what)
{
case 1:
LocalBroadcastManager.this.executePendingBroadcasts();
break;
default:
super.handleMessage(msg);
}
}
};
}
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
{
synchronized (this.mReceivers) {
ReceiverRecord entry = new ReceiverRecord(filter, receiver);
ArrayList filters = (ArrayList)this.mReceivers.get(receiver);
if (filters == null) {
filters = new ArrayList(1);
this.mReceivers.put(receiver, filters);
}
filters.add(filter);
for (int i = 0; i < filter.countActions(); ++i) {
String action = filter.getAction(i);
ArrayList entries = (ArrayList)this.mActions.get(action);
if (entries == null) {
entries = new ArrayList(1);
this.mActions.put(action, entries);
}
entries.add(entry);
}
}
}
public void unregisterReceiver(BroadcastReceiver receiver)
{
synchronized (this.mReceivers) {
ArrayList filters = (ArrayList)this.mReceivers.remove(receiver);
if (filters == null) {
return;
}
for (int i = 0; i < filters.size(); ++i) {
IntentFilter filter = (IntentFilter)filters.get(i);
for (int j = 0; j < filter.countActions(); ++j) {
String action = filter.getAction(j);
ArrayList receivers = (ArrayList)this.mActions.get(action);
if (receivers != null) {
for (int k = 0; k < receivers.size(); ++k) {
if (((ReceiverRecord)receivers.get(k)).receiver == receiver) {
receivers.remove(k);
--k;
}
}
if (receivers.size() <= 0)
this.mActions.remove(action);
}
}
}
}
}
public boolean sendBroadcast(Intent intent)
{
synchronized (this.mReceivers) {
String action = intent.getAction();
String type = intent.resolveTypeIfNeeded(this.mAppContext.getContentResolver());
Uri data = intent.getData();
String scheme = intent.getScheme();
Set categories = intent.getCategories();
boolean debug = (intent.getFlags() & 0x8) != 0;
if (debug) Log.v("LocalBroadcastManager", "Resolving type " + type + " scheme " + scheme + " of intent " + intent);
ArrayList entries = (ArrayList)this.mActions.get(intent.getAction());
if (entries != null) {
if (debug) Log.v("LocalBroadcastManager", "Action list: " + entries);
ArrayList receivers = null;
for (int i = 0; i < entries.size(); ++i) {
ReceiverRecord receiver = (ReceiverRecord)entries.get(i);
if (debug) Log.v("LocalBroadcastManager", "Matching against filter " + receiver.filter);
if (receiver.broadcasting) {
if (debug) {
Log.v("LocalBroadcastManager", " Filter‘s target already added");
}
}
else
{
int match = receiver.filter.match(action, type, scheme, data, categories, "LocalBroadcastManager");
if (match >= 0) {
if (debug) Log.v("LocalBroadcastManager", " Filter matched! match=0x" + Integer.toHexString(match));
if (receivers == null) {
receivers = new ArrayList();
}
receivers.add(receiver);
receiver.broadcasting = true;
} else {
if (!debug)
continue;
String reason;
switch (match)
{
case -3:
reason = "action"; break;
case -4:
reason = "category"; break;
case -2:
reason = "data"; break;
case -1:
reason = "type"; break;
default:
reason = "unknown reason";
}
Log.v("LocalBroadcastManager", " Filter did not match: " + reason);
}
}
}
if (receivers != null) {
for (int i = 0; i < receivers.size(); ++i) {
((ReceiverRecord)receivers.get(i)).broadcasting = false;
}
this.mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
if (!this.mHandler.hasMessages(1)) {
this.mHandler.sendEmptyMessage(1);
}
return true;
}
}
}
return false;
}
public void sendBroadcastSync(Intent intent)
{
if (sendBroadcast(intent))
executePendingBroadcasts();
}
private void executePendingBroadcasts()
{
while (true) {
BroadcastRecord[] brs = null;
synchronized (this.mReceivers) {
int N = this.mPendingBroadcasts.size();
if (N <= 0) {
return;
}
brs = new BroadcastRecord[N];
this.mPendingBroadcasts.toArray(brs);
this.mPendingBroadcasts.clear();
}
for (int i = 0; i < brs.length; ++i) {
BroadcastRecord br = brs[i];
int i;
for (int i = 0; i < br.receivers.size(); ++i)
((ReceiverRecord)br.receivers.get(i)).receiver.onReceive(this.mAppContext, br.intent);
}
}
}
private static class BroadcastRecord
{
final Intent intent;
final ArrayList<LocalBroadcastManager.ReceiverRecord> receivers;
BroadcastRecord(Intent _intent, ArrayList<LocalBroadcastManager.ReceiverRecord> _receivers)
{
this.intent = _intent;
this.receivers = _receivers;
}
}
private static class ReceiverRecord
{
final IntentFilter filter;
final BroadcastReceiver receiver;
boolean broadcasting;
ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver)
{
this.filter = _filter;
this.receiver = _receiver;
}
public String toString()
{
StringBuilder builder = new StringBuilder(128);
builder.append("Receiver{");
builder.append(this.receiver);
builder.append(" filter=");
builder.append(this.filter);
builder.append("}");
return builder.toString();
}
}
}
首先,我们看一下执行流程,先看LocalBroadcastManager 中的部分字段,如下:
private final HashMap<BroadcastReceiver, ArrayList<IntentFilter>> mReceivers = new HashMap();
private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap();
private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList();
通过HashMap 的对象mReceivers 存储广播和过滤器信息,以BroadcastReceiver 作为 key,ArrayList< IntentFilter>为 value。这样做主要是方便取消注册。
通过HashMap的对象mActions 以Action 为 key,ArrayList< ReceiverRecord>为 value。mActions 的主要作用是方便在广播发送后快速得到可以接收它的BroadcastReceiver。
mPendingBroadcasts 这个就不叙述了,就一个存放BroadcastRecord的ArrayList。
构造函数
/**
* created by zero on 2016-07-11
*
* 采用单例,创建一个LocalBroadcastManager对象
*
* 总觉得此处会造成内存泄漏,有人会和我一样这么想吗?(*^__^*) 嘻嘻……
*/
public static LocalBroadcastManager getInstance(Context context) {
/**
* 对于此处的写法,我更喜欢使用双重检查
*/
synchronized (mLock)
{
if (mInstance == null)
{
mInstance = new LocalBroadcastManager(
context.getApplicationContext());
}
return mInstance;
}
}
private LocalBroadcastManager(Context context)
{
this.mAppContext = context;
this.mHandler = new Handler(context.getMainLooper())
{
public void handleMessage(Message msg) {
switch (msg.what)
{
case 1:
LocalBroadcastManager.this.executePendingBroadcasts();
break;
default:
super.handleMessage(msg);
}
}
};
}
此处是基于主线程的 Looper(context.getMainLooper()) new 了一个 Handler,handleMessage 中会调用接收器对广播的消息进行处理,也是 LocalBroadcastManager 的核心部分。
示例代码如下:
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
注册广播:
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
synchronized (this.mReceivers)
{
ReceiverRecord entry = new ReceiverRecord(filter, receiver);
ArrayList filters = (ArrayList) this.mReceivers.get(receiver);
if (filters == null)
{
filters = new ArrayList(1);
this.mReceivers.put(receiver, filters);
}
filters.add(filter);
for (int i = 0; i < filter.countActions(); ++i)
{
String action = filter.getAction(i);
ArrayList entries = (ArrayList) this.mActions.get(action);
if (entries == null)
{
entries = new ArrayList(1);
this.mActions.put(action, entries);
}
entries.add(entry);
}
}
}
通过key去mReceivers中获取ArrayList< IntentFilter>,如果为null,便把传过来的receiver和filters参数put到mReceivers里面,这步骤也便于后面取消注册移除一些必要元素做准备,包括下面对mActions的判断。
示例代码如下:
/**
* created by zero on 2016-07-11
*/
private void rigsterReceiver()
{
// TODO Auto-generated method stub
receiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(ZMIntentAction.MENU_TO_MY))
{
//具体操作
}
}
};
registerLocalBroadcastManagerActionReceiver();
}
private void registerLocalBroadcastManagerActionReceiver()
{
// TODO Auto-generated method stub
final IntentFilter filter = new IntentFilter();
filter.addAction(ZMIntentAction.MENU_TO_HOME);
filter.addAction(ZMIntentAction.MENU_TO_MY);
LocalBroadcastManager.getInstance(this).registerReceiver(
receiver, filter);
}
取消注册:
public void unregisterReceiver(BroadcastReceiver receiver) {
synchronized (this.mReceivers)
{
ArrayList filters = (ArrayList) this.mReceivers.remove(receiver);
if (filters == null)
{
return;
}
for (int i = 0; i < filters.size(); ++i)
{
IntentFilter filter = (IntentFilter) filters.get(i);
for (int j = 0; j < filter.countActions(); ++j)
{
String action = filter.getAction(j);
ArrayList receivers = (ArrayList) this.mActions.get(action);
if (receivers != null)
{
for (int k = 0; k < receivers.size(); ++k)
{
if (((ReceiverRecord) receivers.get(k)).receiver == receiver)
{
receivers.remove(k);
--k;
}
}
if (receivers.size() <= 0)
this.mActions.remove(action);
}
}
}
}
}
取消注册,其实就是从mReceivers 及mActions 中移除相应元素而已,与上述的注册相对应,一个是添加操作,一个是移除操作。
示例代码如下:
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
发送广播:
public boolean sendBroadcast(Intent intent) {
synchronized (this.mReceivers)
{
String action = intent.getAction();
String type = intent.resolveTypeIfNeeded(this.mAppContext
.getContentResolver());
Uri data = intent.getData();
String scheme = intent.getScheme();
Set categories = intent.getCategories();
boolean debug = (intent.getFlags() & 0x8) != 0;
if (debug)
Log.v("LocalBroadcastManager", "Resolving type " + type
+ " scheme " + scheme + " of intent " + intent);
ArrayList entries = (ArrayList) this.mActions.get(intent
.getAction());
if (entries != null)
{
if (debug)
Log.v("LocalBroadcastManager", "Action list: " + entries);
ArrayList receivers = null;
for (int i = 0; i < entries.size(); ++i)
{
ReceiverRecord receiver = (ReceiverRecord) entries.get(i);
if (debug)
Log.v("LocalBroadcastManager",
"Matching against filter " + receiver.filter);
if (receiver.broadcasting)
{
if (debug)
{
Log.v("LocalBroadcastManager",
" Filter‘s target already added");
}
} else
{
int match = receiver.filter.match(action, type, scheme,
data, categories, "LocalBroadcastManager");
if (match >= 0)
{
if (debug)
Log.v("LocalBroadcastManager",
" Filter matched! match=0x"
+ Integer.toHexString(match));
if (receivers == null)
{
receivers = new ArrayList();
}
receivers.add(receiver);
receiver.broadcasting = true;
} else
{
if (!debug)
continue;
String reason;
switch (match)
{
case -3:
reason = "action";
break;
case -4:
reason = "category";
break;
case -2:
reason = "data";
break;
case -1:
reason = "type";
break;
default:
reason = "unknown reason";
}
Log.v("LocalBroadcastManager",
" Filter did not match: " + reason);
}
}
}
if (receivers != null)
{
for (int i = 0; i < receivers.size(); ++i)
{
((ReceiverRecord) receivers.get(i)).broadcasting = false;
}
this.mPendingBroadcasts.add(new BroadcastRecord(intent,
receivers));
if (!this.mHandler.hasMessages(1))
{
this.mHandler.sendEmptyMessage(1);
}
return true;
}
}
}
return false;
}
先根据Action 从mActions 中取出ReceiverRecord 列表,循环每个ReceiverRecord 判断 filter 和 intent 中的 action、type、scheme、data、categoried 是否 match,是的话则保存到receivers列表中,发送 what 为MSG_EXEC_PENDING_BROADCASTS的消息,通过 Handler 去处理。
示例代码如下:
LocalBroadcastManager.getInstance(this)
.sendBroadcast(new Intent(ZMIntentAction.MENU_TO_HOME));
消息处理:
private void executePendingBroadcasts() {
while (true)
{
BroadcastRecord[] brs = null;
synchronized (this.mReceivers)
{
int N = this.mPendingBroadcasts.size();
if (N <= 0)
{
return;
}
brs = new BroadcastRecord[N];
this.mPendingBroadcasts.toArray(brs);
this.mPendingBroadcasts.clear();
}
for (int i = 0; i < brs.length; ++i)
{
BroadcastRecord br = brs[i];
// 这里真心没看懂,这样写,会报Duplicate local variable i错误
int i;
for (int i = 0; i < br.receivers.size(); ++i)
((ReceiverRecord) br.receivers.get(i)).receiver.onReceive(
this.mAppContext, br.intent);
}
}
}
以上为消息处理的函数。mPendingBroadcasts 转换为数组BroadcastRecord,循环每个receiver,调用其onReceive 函数,这样便完成了广播的核心逻辑。
最后说下LocalBroadcastManager和BroadcastReceiver 的根本区别,BroadcastReceiver 的通信是走 Binder 机制,所以可以跨进程通信(Binder 机制在此不叙述,有兴趣的可以自己查下资料),LocalBroadcastManager 核心实现实际还是 Handler,因为是 Handler 实现的应用内的通信,这就可以理解上述所说的三个优点,本APP通信、不受非本APP广播影响、效率高,并且无法跨进程通信。