LocalBroadcastManager
本地广播,用于应用内部通信,可以实现线程间交互。
标准的广播 BroadcastReceiver
用于跨进程通信,不同应用之间的通信,实现原理基于 Binder
机制。而同一个应用相同进程内,通过观察者模式来实现消息传递,并不需要全局广播,在 support.v4
包中提供的 LocalBroadcastManager
就是用来实现本地广播的,它是基于 Handler
机制,实现线程间通信,Handler.mLooper
为应用的主线程 Looper
。
LocalBroadcastManager
本地广播通过 Handler
逐条处理广播的(串行处理方式),它支持异步和同步处理方式。
内部类
ReceiverRecord
广播接收器记录
ReceiverRecord
类存储了一个广播接收器,及其对应的过滤器。
BroadcastReceiver receiver
:注册的广播接收器
IntentFilter filter
:注册广播接收器时对应过滤器
broadcasting
:表示是否正在处理对应的广播,避免重复处理
1 2 3 4 5 6 7 8 9 10 11 12 13
| private static class ReceiverRecord { final IntentFilter filter; final BroadcastReceiver receiver; boolean broadcasting;
ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver){ filter = _filter; receiver = _receiver; }
@Override public String toString() {...} }
|
BroadcastRecord
广播发送记录
ReceiverRecord
类存储了一个广播 Intent
,及其匹配的所有广播接收器记录列表。
Intent intent
:记录发送的广播
ArrayList<ReceiverRecord> receivers
:匹配该广播的所有接收器列表
1 2 3 4 5 6 7 8 9
| private static class BroadcastRecord { final Intent intent; final ArrayList<ReceiverRecord> receivers;
BroadcastRecord(Intent _intent, ArrayList<ReceiverRecord> _receivers){ intent = _intent; receivers = _receivers; } }
|
成员变量和构造方法
源码列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| private final Context mAppContext;
private final HashMap<BroadcastReceiver,ArrayList<IntentFilter>> mReceivers = new HashMap<BroadcastReceiver, ArrayList<IntentFilter>>();
private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<String, ArrayList<ReceiverRecord>>();
private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<BroadcastRecord>();
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) { 整个应用的 Context 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); } } }; }
|
重要成员变量
mAppContext
:整个应用的 Context
,避免组件退出引起内存泄露
mReceivers
:哈希表,存储应用所有的广播接收器,及每个广播接收器对应的广播过滤器列表(一个广播接收器可以监听多个广播)
mActions
:哈希表,存储应用所有的广播,及每条广播对应的广播接收器列表(一个广播可以有多个广播接收器响应)
mPendingBroadcasts
:数组列表,记录需要处理广播
mHandler
:使用 Handler
通信机制来处理应用内部的所有本地广播,Looper
对应的是应用主线程 Looper
单例模式
LocalBroadcastManager
的构造方法是私有的,使用单例模式来获取实例。构造方法中,实例化 Handler
并实现消息处理方法。(这里单例模式更推荐双检锁实现方式)
注册/取消注册广播
注册广播
注册广播的过程,就是一个数据存储过程。
- 根据注册的广播接收器和过滤器,新建
ReceiverRecord
对象
- 将广播接收器和过滤器,存储到
mReceivers
中
- 将广播过滤器的
Action
存储到 mActions
中,方便后续根据 Action
查找对应的广播接收器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { synchronized (mReceivers) { ReceiverRecord entry = new ReceiverRecord(filter, receiver); ArrayList<IntentFilter> filters = mReceivers.get(receiver); if (filters == null) { filters = new ArrayList<IntentFilter>(1); mReceivers.put(receiver, filters); } filters.add(filter); 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); } } }
|
取消广播注册
取消广播注册,就是一个移除数据的过程。
- 从
mReceivers
中移除该广播接收器
- 从
mActions
中移除该广播接收器监听的广播过滤器列表中每个 Action
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public void unregisterReceiver(BroadcastReceiver receiver) { synchronized (mReceivers) { ArrayList<IntentFilter> filters = mReceivers.remove(receiver); if (filters == null) { return; } for (int i=0; i<filters.size(); i++) { IntentFilter filter = filters.get(i); for (int j=0; j<filter.countActions(); j++) { String action = filter.getAction(j); ArrayList<ReceiverRecord> receivers=mActions.get(action); if (receivers != null) { for (int k=0; k<receivers.size(); k++) { if (receivers.get(k).receiver == receiver) { receivers.remove(k); k--; } } if (receivers.size() <= 0) { mActions.remove(action); } } } } } }
|
发送广播
发送广播
广播的发送有两种:同步和异步发送;异步发送是通过 Handler.sendEmptyMessage
实现,而同步则是在异步的基础上,马上执行广播接收器响应(主要是在异步出现阻塞或者之前有过多任务时,才能体现出明显的效率)。
- 从
mActions
中查找广播对应的广播接收记录列表
- 每个广播接收记录中,如果不是正在被广播,则添加到
mPendingBroadcasts
中
Handler
发送消息,异步执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| 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 (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 { ... } }
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; }
public void sendBroadcastSync(Intent intent) { if (sendBroadcast(intent)) { executePendingBroadcasts(); } }
|
sendBroadcastSync
同步广播,如果有广播在排队处理,直接调用广播执行方法 executePendingBroadcasts
;如果广播队列并没有等待,效率区别不大。
响应广播
不管是同步广播还是异步广播,最终响应执行都是调用 executePendingBroadcasts
方法。主要功能是:从 mPendingBroadcasts
中逐个取出广播接收器,响应 BroadcastReceiver.onReceive
回调方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| private void executePendingBroadcasts() { while (true) { BroadcastRecord[] brs = null; 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++) { BroadcastRecord br = brs[i]; for (int j=0; j<br.receivers.size(); j++) { br.receivers.get(j).receiver. onReceive(mAppContext, br.intent); } } } }
|
示例
在 Activity
中注册一个广播接收器,在 Services
后台线程中发送本地广播,形成线程间本地广播通信。
广播注册/取消注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
private LocalBroadcastManager mLocalBroadcastManager = null; private boolean mRegistered; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent != null){ String response = intent.getStringExtra("key"); Log.d(TAG, "onReceive: response: " + response); } } };
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_local_broadcast); mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); }
@Override protected void onStart() { super.onStart(); IntentFilter intentFilter = new IntentFilter(ACTION_RESPONSE); mLocalBroadcastManager.registerReceiver(mReceiver, intentFilter); mRegistered = true; }
@Override protected void onStop() { super.onStop(); if (mRegistered){ mRegistered = false; mLocalBroadcastManager.unregisterReceiver(mReceiver); Log.d(TAG, "onStop: mLocalBroadcastManager.unregisterReceiver"); } }
|
广播发送
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| private void doLongWork(final String value){ new Thread(new Runnable() { @Override public void run() { Log.d(TAG, "run: sleep..."); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } Intent intent = new Intent(ACTION_RESPONSE); intent.putExtra("key", "response"); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } }).start(); }
|
小结
本地广播的三个特点:
- 数据只会在当前应用中广播,不会传递到其他应用(甚至当前应用的其他进程),确保数据安全
- 其他应用的广播不会发送到当前应用中,不用担心安全漏洞
- 不用通过系统
AMS
全局管理广播,而是本地保存数据,广播更高效
另外:本地广播只支持动态注册的方式。
参考文档