分析廣播工作原理端辱,我們大致分為兩個(gè)模塊梁剔,一個(gè)是LocalBroadcastManager控制的虽画、只能在進(jìn)程內(nèi)通信的廣播機(jī)制,另外一個(gè)還是通過ActivityManagerService作為中轉(zhuǎn)的荣病、可以在進(jìn)程間通信的廣播機(jī)制码撰。
LocalBroadcastManager控制的應(yīng)用內(nèi)廣播機(jī)制
本地廣播整體邏輯比較簡(jiǎn)單,關(guān)鍵代碼基本都在LocalBroadcastManager類中个盆,基本上簡(jiǎn)略瀏覽一遍源碼就能搞清楚里面的實(shí)現(xiàn)邏輯脖岛,此處先給出LocalBroadcastManager的源碼:
public final class LocalBroadcastManager {
private static final class ReceiverRecord {
final IntentFilter filter;
final BroadcastReceiver receiver;
boolean broadcasting;
boolean dead;
ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) {
filter = _filter;
receiver = _receiver;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder(128);
builder.append("Receiver{");
builder.append(receiver);
builder.append(" filter=");
builder.append(filter);
if (dead) {
builder.append(" DEAD");
}
builder.append("}");
return builder.toString();
}
}
private static final class BroadcastRecord {
final Intent intent;
final ArrayList<ReceiverRecord> receivers;
BroadcastRecord(Intent _intent, ArrayList<ReceiverRecord> _receivers) {
intent = _intent;
receivers = _receivers;
}
}
private static final String TAG = "LocalBroadcastManager";
private static final boolean DEBUG = false;
private final Context mAppContext;
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<>();
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) {
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);
}
}
};
}
/**
* Register a receive for any local broadcasts that match the given IntentFilter.
*
* @param receiver The BroadcastReceiver to handle the broadcast.
* @param filter Selects the Intent broadcasts to be received.
*
* @see #unregisterReceiver
*/
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
synchronized (mReceivers) {
ReceiverRecord entry = new ReceiverRecord(filter, receiver);
ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
if (filters == null) {
filters = new ArrayList<>(1);
mReceivers.put(receiver, filters);
}
filters.add(entry);
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);
}
}
}
/**
* Unregister a previously registered BroadcastReceiver. <em>All</em>
* filters that have been registered for this BroadcastReceiver will be
* removed.
*
* @param receiver The BroadcastReceiver to unregister.
*
* @see #registerReceiver
*/
public void unregisterReceiver(BroadcastReceiver receiver) {
synchronized (mReceivers) {
final ArrayList<ReceiverRecord> filters = mReceivers.remove(receiver);
if (filters == null) {
return;
}
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);
}
}
}
}
}
}
/**
* Broadcast the given intent to all interested BroadcastReceivers. This
* call is asynchronous; it returns immediately, and you will continue
* executing while the receivers are run.
*
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast.
*
* @see #registerReceiver
*
* @return Returns true if the intent has been scheduled for delivery to one or more
* broadcast receivers. (Note tha delivery may not ultimately take place if one of those
* receivers is unregistered before it is dispatched.)
*/
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();
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);
ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
if (entries != null) {
if (debug) Log.v(TAG, "Action list: " + entries);
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);
if (receiver.broadcasting) {
if (debug) {
Log.v(TAG, " Filter's target already added");
}
continue;
}
int match = receiver.filter.match(action, type, scheme, data,
categories, "LocalBroadcastManager");
if (match >= 0) {
if (debug) Log.v(TAG, " Filter matched! match=0x" +
Integer.toHexString(match));
if (receivers == null) {
receivers = new ArrayList<ReceiverRecord>();
}
receivers.add(receiver);
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++) {
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;
}
/**
* Like {@link #sendBroadcast(Intent)}, but if there are any receivers for
* the Intent this function will block and immediately dispatch them before
* returning.
*/
public void sendBroadcastSync(Intent intent) {
if (sendBroadcast(intent)) {
executePendingBroadcasts();
}
}
private void executePendingBroadcasts() {
while (true) {
final BroadcastRecord[] brs;
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++) {
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) {
rec.receiver.onReceive(mAppContext, br.intent);
}
}
}
}
}
}
LocalBroadcastManager 采用單例模式,從源頭上統(tǒng)一了廣播的發(fā)送和接收颊亮。從上面源碼可以看出柴梆,LocalBroadcastManager 創(chuàng)建了兩個(gè)內(nèi)部類ReceiverRecord 和BroadcastRecord 來記錄廣播接收者和廣播Intent對(duì)應(yīng)的實(shí)體,并且初始化了三個(gè)HashMap對(duì)象mReceivers终惑、mActions和mPendingBroadcasts來分別保存BroadcastReceiver與ReceiverRecord 的關(guān)系绍在、Action與ReceiverRecord 的關(guān)系以及待發(fā)送Intent內(nèi)容對(duì)應(yīng)的BroadcastRecord ;其中mReceivers在發(fā)送廣播邏輯中作用并不是特別大雹有,主要作為同步鎖和保存偿渡、移除數(shù)據(jù)用。
其實(shí)當(dāng)我們看到上面的HashMap時(shí)基本上就可以自己在大腦中有個(gè)基本的實(shí)現(xiàn)邏輯了霸奕,無非就是通過對(duì)mActions溜宽、mPendingBroadcasts集合進(jìn)行增刪改查,最終實(shí)現(xiàn)對(duì)應(yīng)的注冊(cè)铅祸、發(fā)送以及反注冊(cè)等操作坑质,事實(shí)上里面的邏輯也就是這些操作組合而成的合武。
接下來我們就按平時(shí)的接口調(diào)用順序來一一查看源碼:
registerReceiver方法
一般我們使用本地廣播首先就是先注冊(cè)临梗,而注冊(cè)方法registerReceiver的邏輯其實(shí)也很簡(jiǎn)單,無非就是往mReceivers和mActions添加預(yù)置關(guān)系稼跳,方便之后發(fā)送廣播時(shí)快速查找對(duì)應(yīng)的廣播接收者:
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
synchronized (mReceivers) {
ReceiverRecord entry = new ReceiverRecord(filter, receiver);
ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
if (filters == null) {
filters = new ArrayList<>(1);
mReceivers.put(receiver, filters);
}
filters.add(entry);
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方法
有注冊(cè)就有反注冊(cè)盟庞,通常反注冊(cè)就是為了釋放相關(guān)對(duì)象的關(guān)聯(lián),減少相應(yīng)時(shí)間和內(nèi)存開銷汤善,避免產(chǎn)生內(nèi)存泄漏的問題什猖。而此處的反注冊(cè)也不例外,主要用來清除掉不再使用的廣播接收者相關(guān)信息红淡,
public void unregisterReceiver(BroadcastReceiver receiver) {
synchronized (mReceivers) {
final ArrayList<ReceiverRecord> filters = mReceivers.remove(receiver);
if (filters == null) {
return;
}
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方法
整個(gè)流程中不狮,最重要的方法就是sendBroadcast,里面的流程是本地廣播的核心機(jī)制在旱,但其實(shí)里面的邏輯卻也很簡(jiǎn)單摇零!無非就是對(duì)mActions的“查”以及對(duì)mPendingBroadcasts的“增”和“查”。
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();
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);
ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
if (entries != null) {
if (debug) Log.v(TAG, "Action list: " + entries);
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);
if (receiver.broadcasting) {
if (debug) {
Log.v(TAG, " Filter's target already added");
}
continue;
}
int match = receiver.filter.match(action, type, scheme, data,
categories, "LocalBroadcastManager");
if (match >= 0) {
if (debug) Log.v(TAG, " Filter matched! match=0x" +
Integer.toHexString(match));
if (receivers == null) {
receivers = new ArrayList<ReceiverRecord>();
}
receivers.add(receiver);
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++) {
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;
}
閱讀源碼我們可以發(fā)現(xiàn)桶蝎,整個(gè)流程中首先從Intent拿到Action驻仅,然后從mActions中找到key為Action的廣播接收者列表谅畅,接著拿列表中的各個(gè)廣播接收者與intent中攜帶的相關(guān)信息進(jìn)行匹配,匹配成功則添加進(jìn)新的廣播接收者列表receivers 中噪服,最后用receivers生成BroadcastRecord對(duì)象并添加進(jìn)mPendingBroadcasts中毡泻,mHandler發(fā)送消息MSG_EXEC_PENDING_BROADCASTS觸發(fā)主線程執(zhí)行。
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);
}
}
};
}
private void executePendingBroadcasts() {
while (true) {
final BroadcastRecord[] brs;
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++) {
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) {
rec.receiver.onReceive(mAppContext, br.intent);
}
}
}
}
}
mHandler 收到消息后最終執(zhí)行到了executePendingBroadcasts方法粘优;然后你會(huì)很驚訝的發(fā)現(xiàn)仇味,這居然用了一個(gè)死循環(huán),當(dāng)然也添加了打斷條件(mPendingBroadcasts.size()為0的時(shí)候)雹顺。在同步鎖的情況下用mPendingBroadcasts生成了一個(gè)BroadcastRecord[]數(shù)組brs邪铲,然后清空了mPendingBroadcasts的數(shù)據(jù),這樣做的是為了避免直接操作mPendingBroadcasts的數(shù)據(jù)進(jìn)而造成數(shù)據(jù)混亂无拗,最后雙重遍歷brs找到receiver并回調(diào)onReceive方法带到。
到此本地廣播的源碼基本上已經(jīng)看完了,你會(huì)發(fā)現(xiàn)LocalBroadcastManager沒有涉及到靜態(tài)廣播的東西英染,所以靜態(tài)注冊(cè)的廣播接收者是接收不到本地廣播的揽惹;同時(shí)mHandler 的使用也證明了onReceive是跑在主線程的弯菊;本地廣播的onReceive是一個(gè)個(gè)串行跑的谊却,不存在并行的情況.