关于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广播影响、效率高,并且无法跨进程通信。