接上篇文章,這篇文章主要是總結前面知識,並且瞭解一些細節問題,加深對廣播機制的理解,比如有播有序是怎麼保證有序的?廣播攔截機制是怎麼實現的?廣播傳送超時了是怎麼處理的?registerReceiver方法發返回值有什麼用?粘性廣播等等。
Android原始碼解析四大元件系列(五)---廣播的註冊過程
Android原始碼解析四大元件系列(六)---廣播的處理過程
Android原始碼解析四大元件系列(七)---廣播的傳送過程
###1、廣播相關資料結構的再次理解
ReceiverDispatcher: 客戶端廣播分發者物件,第一篇講的很清楚了,ReceiverDispatcher的內部類InnerReceiver為binder物件,用於與AMS的傳遞與通訊。
ReceiverList: 繼承自ArrayList,存放了Receiver的binder物件以及其註冊的BroadcastFilter列表。AMS中定義了
final HashMapmRegisteredReceivers = new HashMap<>();key為InnerReceiver的binder物件,值為ReceiverList,ReceiverList內部記錄的是動態註冊的廣播接收者,mRegisteredReceivers只有動態註冊的時候才會有內容。 BroadcastFilter: 封裝了IntentFilter,描述動態廣播,是動態廣播節點。
ResolveInfo:Parcelable子類,描述靜態廣播,是靜態廣播節點。
IntentResolver: 解析Intent,在addFilter時即進行解析。其內部有mSchemeToFilter,mActionToFilter,mTypedActionToFilter三個map物件。key為對應的action(scheme或者type),value為Filter。
BroadcastRecord:描述一個廣播, 將intent等一堆資訊,封裝成BroadcastRecord,交給BroadcastQueue進行處理。
BroadcastQueue: BroadcastQueue為Broadcast處理佇列,分為前臺佇列mFgBroadcastQueue和後臺佇列mBgBroadcastQueue,mFgBroadcastQueue會有更高的許可權,被優先處理。mFgBroadcastQueue和mBgBroadcastQueue兩個佇列中都含有mOrderedBroadcasts和mParallelBroadcasts兩個列表用來表示有序廣播列表和無序廣播列表。
###2、有序廣播是怎麼保證有序的
上一篇文章中說了processNextBroadcast()只會處理一個BroadcastRecord的一個receiver,那怎麼將廣播傳遞給下一個receiver呢?廣播接受者有“動態”和“靜態”之分,廣播訊息也有“序列”和“並行”之分,或者叫“有序”和“無序”之分。廣播的處理方式跟廣播的接收者和廣播訊息型別有關係。有序廣播是怎麼保證有序的這個問題,得分情況討論,對於動態註冊的receiver,先回到最終onReceive回撥的地方,分析如下:
static final class ReceiverDispatcher {
.....
final class Args extends BroadcastReceiver.PendingResult implements Runnable {
.....
public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, int sendingUser) {
//mRegistered傳進來的是true
super(resultCode, resultData, resultExtras,
mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
mCurIntent = intent;
mOrdered = ordered;
}
public void run() {
.....
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
//廣播的onReceive方法回撥
receiver.onReceive(mContext, intent);
} catch (Exception e) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing failed broadcast to " + mReceiver);
sendFinished(mgr);
}
if (mInstrumentation == null ||
!mInstrumentation.onException(mReceiver, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Error receiving broadcast " + intent
+ " in " + mReceiver, e);
}
}
if (receiver.getPendingResult() != null) {
finish();
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
}複製程式碼
因為在呼叫onReceive之前,執行了 receiver.setPendingResult(this),所以在下面receiver.getPendingResult()就不是null,則就進入BroadcastReceiver的內部類PendingResult的finish方法。
public final void finish() {
if (mType == TYPE_COMPONENT) {
final IActivityManager mgr = ActivityManagerNative.getDefault();
if (QueuedWork.hasPendingWork()) {
......
QueuedWork.singleThreadExecutor().execute( new Runnable() {
@Override public void run() {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast after work to component " + mToken);
sendFinished(mgr);
}
});
} else {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to component " + mToken);
sendFinished(mgr);
}
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to " + mToken);
final IActivityManager mgr = ActivityManagerNative.getDefault();
sendFinished(mgr);
}
}複製程式碼
finish方法中根據mType的值有兩個分支。mType是PendingResult的成員變數,在PendingResult的建構函式中進行賦值的。
public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type,
boolean ordered, boolean sticky, IBinder token, int userId, int flags) {
mResultCode = resultCode;
mResultData = resultData;
mResultExtras = resultExtras;
mType = type;
mOrderedHint = ordered;
mInitialStickyHint = sticky;
mToken = token;
mSendingUser = userId;
mFlags = flags;
}複製程式碼
這個構造方法是在BroadcastReceiver.PendingResult的子類Args中呼叫的
final class Args extends BroadcastReceiver.PendingResult implements Runnable {
private Intent mCurIntent;
private final boolean mOrdered;
private boolean mDispatched;
public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, int sendingUser) {
super(resultCode, resultData, resultExtras,
mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
mCurIntent = intent;
mOrdered = ordered;
}
}複製程式碼
由於mRegistered是動態註冊廣播接收者傳進來的,值是true,所以上面mType的值是TYPE_REGISTERED,由於是有序廣播ordered值是true,那麼mOrderedHint為true,所以要走第二個分支:
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to " + mToken);
final IActivityManager mgr = ActivityManagerNative.getDefault();
sendFinished(mgr);複製程式碼
BroadcastReceiver的sendFinished方法如下:
public void sendFinished(IActivityManager am) {
synchronized (this) {
if (mFinished) {
throw new IllegalStateException("Broadcast already finished");
}
mFinished = true;
try {
if (mResultExtras != null) {
mResultExtras.setAllowFds(false);
}
if (mOrderedHint) {
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
mAbortBroadcast, mFlags);
} else {
// This broadcast was sent to a component; it is not ordered,
// but we still need to tell the activity manager we are done.
am.finishReceiver(mToken, 0, null, null, false, mFlags);
}
} catch (RemoteException ex) {
}
}
}複製程式碼
有序廣播mOrderedHint值為true,所以進入到AMS的finishReceiver方法。
public void finishReceiver(IBinder who, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort, int flags) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);
// Refuse possible leaked file descriptors
if (resultExtras != null && resultExtras.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
}
final long origId = Binder.clearCallingIdentity();
try {
boolean doNext = false;
BroadcastRecord r;
synchronized(this) {
BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
? mFgBroadcastQueue : mBgBroadcastQueue;
r = queue.getMatchingOrderedReceiver(who);
if (r != null) {
doNext = r.queue.finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, true);
}
}
if (doNext) {
//再次執行processNextBroadcast處理廣播
r.queue.processNextBroadcast(false);
}
trimApplications();
} finally {
Binder.restoreCallingIdentity(origId);
}
}複製程式碼
上面是分析了動態的廣播接收者是怎麼按照一個接著一個處理的。在看看靜態註冊的receiver,回到靜態廣播回撥onReceive方法的地方。
private void handleReceiver(ReceiverData data) {
....
IActivityManager mgr = ActivityManagerNative.getDefault();
BroadcastReceiver receiver;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess();
data.setExtrasClassLoader(cl);
//反射出BroadcastReceiver
receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
} catch (Exception e) {
....
}
try {
Application app = packageInfo.makeApplication(false, mInstrumentation);
....
ContextImpl context = (ContextImpl)app.getBaseContext();
sCurrentBroadcastIntent.set(data.intent);
receiver.setPendingResult(data);
//回撥廣播的onReceive方法
receiver.onReceive(context.getReceiverRestrictedContext(),data.intent);
} catch (Exception e) {
....
}
} finally {
sCurrentBroadcastIntent.set(null);
}
if (receiver.getPendingResult() != null) {
data.finish();
}
}複製程式碼
在回撥onReceiver方法之前, 執行了 receiver.setPendingResult(data),所以下面receiver.getPendingResult() != null成立,走 data.finish(),data是ReceiverData物件,handleReceiver方法傳進來的,在scheduleReceiver方法中初始化。
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
boolean sync, int sendingUser, int processState) {
updateProcessState(processState, false);
ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
sync, false, mAppThread.asBinder(), sendingUser);
r.info = info;
r.compatInfo = compatInfo;
sendMessage(H.RECEIVER, r);
}複製程式碼
我們看 data.finish()方法
public final void finish() {
if (mType == TYPE_COMPONENT) {
final IActivityManager mgr = ActivityManagerNative.getDefault();
if (QueuedWork.hasPendingWork()) {
QueuedWork.singleThreadExecutor().execute( new Runnable() {
@Override public void run() {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast after work to component " + mToken);
sendFinished(mgr);
}
});
} else {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to component " + mToken);
sendFinished(mgr);
}
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to " + mToken);
final IActivityManager mgr = ActivityManagerNative.getDefault();
sendFinished(mgr);
}
}複製程式碼
此時mType分析後值是TYPE_COMPONENT,同樣會走sendFinished,後面AMS的處理邏輯是一樣的,不贅述。
###3、廣播超時是怎麼處理的?
AMS維護了兩個廣播佇列BroadcastQueue,mFgBroadcastQueue,前臺佇列的超時時間是10秒,mBgBroadcastQueue,後臺佇列的超時時間是60秒,如果廣播沒有在規定的時間內處理完就會發生ANR,如果你想你的廣播進入前臺廣播佇列,那麼在傳送的時候,在intent中加入Intent.FLAG_RECEIVER_FOREGROUND標記,如果不加,系統預設是後臺廣播。mFgBroadcastQueue會有更高的許可權,被優先處理。
在processNextBroadcast方法中有下面一段程式碼,與廣播超時有關係,一旦超時就會出現ANR。
do {
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
if (mService.mProcessesReady && r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
//廣播訊息的第一個ANR監測機制
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
Slog.w(TAG, "Hung broadcast ["
+ mQueueName + "] discarded after timeout failure:"
+ " now=" + now
+ " dispatchTime=" + r.dispatchTime
+ " startTime=" + r.receiverTime
+ " intent=" + r.intent
+ " numReceivers=" + numReceivers
+ " nextReceiver=" + r.nextReceiver
+ " state=" + r.state);
broadcastTimeoutLocked(false); // 超時處理
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
}
//判斷廣播有沒有處理完畢
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
// No more receivers for this broadcast! Send the final
// result if requested...
if (r.resultTo != null) {
try {
performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode r.resultData, r.resultExtras, false, false, r.userId);
r.resultTo = null;
} catch (RemoteException e) {
......
}
}
} while (r == null);複製程式碼
廣播的超時機制是針對有序廣播來說的,無序廣播一次性全部處理了,肯定不會超時,超時的這段邏輯都在broadcastTimeoutLocked中,首先判斷是否超時,公式:r.dispatchTime + 2×mTimeoutPeriod×numReceivers,現在解釋一下這幾個時間:
dispatchTime的意義是標記實際處理BroadcastRecord的起始時間,有序廣播是一個接著一個進行處理的,第一次dispatchTime=0,並不會進入該條件判斷
mTimeoutPeriod由當前BroadcastQueue的型別決定(mFgBroadcastQueue為10秒,mBgBroadcastQueue為60秒)
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;
mFgBroadcastQueue = new BroadcastQueue(this, mHandler, "foreground", BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler, "background", BROADCAST_BG_TIMEOUT, true);複製程式碼
所以上面公式翻譯過來就是:實際處理BroadcastRecord的起始時間+廣播預設的超時時間*廣播接收者的數量。話說回來,這個公式為什麼要這麼設計呢?如果一個前臺的廣播訊息有兩個接收者,那麼在20秒(2 x 10)之內搞定就可以了,也可能第一個訊息執行了15秒,第二個訊息執行4.99秒,即使第一訊息超過了10秒的規定,也不會出現ANR。但是系統任務繁忙,可能有其他活要幹,我們要儘可能的減少ANR的發生,所以前面乘以2倍。
假設現在廣播超時還沒處理,滿足if條件,就會進入,列印Hung broadcast ["+ mQueueName + "] discarded after timeout failure....的log,然後執行 broadcastTimeoutLocked(false)強制停止廣播,broadcastTimeoutLocked相關程式碼程式碼如下:
final void broadcastTimeoutLocked(boolean fromMsg) {
.....
long timeoutTime = r.receiverTime + mTimeoutPeriod;
if (timeoutTime > now) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Premature timeout ["
+ mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
+ timeoutTime);
setBroadcastTimeoutLocked(timeoutTime);
return;
}
}
.....
}複製程式碼
內部呼叫setBroadcastTimeoutLocked()設定一個延遲訊息
final void setBroadcastTimeoutLocked(long timeoutTime) {
if (! mPendingBroadcastTimeoutMessage) {
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
mHandler.sendMessageAtTime(msg, timeoutTime);
mPendingBroadcastTimeoutMessage = true;
}
}複製程式碼
如果廣播訊息能夠處理完畢,就會執行cancelBroadcastTimeoutLocked,將超時的Message移除掉。
final void cancelBroadcastTimeoutLocked() {
if (mPendingBroadcastTimeoutMessage) {
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
mPendingBroadcastTimeoutMessage = false;
}複製程式碼
如果廣播訊息沒有在timeout時間內處理掉,下面BroadcastHandler傳送的訊息就會執行。
private final class BroadcastHandler extends Handler {
.....
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
.....
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
.....
}
}
}複製程式碼
再次進入broadcastTimeoutLocked方法裡面
final void broadcastTimeoutLocked(boolean fromMsg) {
//傳進來是ture
if (fromMsg) {
mPendingBroadcastTimeoutMessage = false;
}
//佇列沒有廣播處理了,返回
if (mOrderedBroadcasts.size() == 0) {
return;
}
long now = SystemClock.uptimeMillis();
BroadcastRecord r = mOrderedBroadcasts.get(0);
if (fromMsg) {
//正在執行dexopt,返回
if (mService.mDidDexOpt) {
// Delay timeouts until dexopt finishes.
mService.mDidDexOpt = false;
long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
setBroadcastTimeoutLocked(timeoutTime);
return;
}
//系統還沒有進入ready狀態
if (!mService.mProcessesReady) {
// Only process broadcast timeouts if the system is ready. That way
// PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
// to do heavy lifting for system up.
return;
}
//如果當前正在執行的receiver沒有超時,則重新設定廣播超時
long timeoutTime = r.receiverTime + mTimeoutPeriod;
if (timeoutTime > now) {
// We can observe premature timeouts because we do not cancel and reset the
// broadcast timeout message after each receiver finishes. Instead, we set up
// an initial timeout then kick it down the road a little further as needed
// when it expires.
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Premature timeout ["
+ mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
+ timeoutTime);
setBroadcastTimeoutLocked(timeoutTime);
return;
}
}
//當前正在執行的receiver沒有超時,則重新設定廣播超時,處理下一條廣播
BroadcastRecord br = mOrderedBroadcasts.get(0);
if (br.state == BroadcastRecord.WAITING_SERVICES) {
// In this case the broadcast had already finished, but we had decided to wait
// for started services to finish as well before going on. So if we have actually
// waited long enough time timeout the broadcast, let's give up on the whole thing
// and just move on to the next.
Slog.i(TAG, "Waited long enough for: " + (br.curComponent != null
? br.curComponent.flattenToShortString() : "(null)"));
br.curComponent = null;
br.state = BroadcastRecord.IDLE;
processNextBroadcast(false);
return;
}
Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r. receiver
+ ", started " + (now - r.receiverTime) + "ms ago");
r.receiverTime = now;
r.anrCount++;
// Current receiver has passed its expiration date.
if (r.nextReceiver <= 0) {
Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
return;
}
ProcessRecord app = null;
String anrMessage = null;
Object curReceiver = r.receivers.get(r.nextReceiver-1);
r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
Slog.w(TAG, "Receiver during timeout: " + curReceiver);
logBroadcastReceiverDiscardLocked(r);
if (curReceiver instanceof BroadcastFilter) {
BroadcastFilter bf = (BroadcastFilter)curReceiver;
if (bf.receiverList.pid != 0
&& bf.receiverList.pid != ActivityManagerService.MY_PID) {
synchronized (mService.mPidsSelfLocked) {
app = mService.mPidsSelfLocked.get(
bf.receiverList.pid);
}
}
} else {
app = r.curApp;
}
//程式存在,anrMessage賦值
if (app != null) {
anrMessage = "Broadcast of " + r.intent.toString();
}
if (mPendingBroadcast == r) {
mPendingBroadcast = null;
}
// Move on to the next receiver.
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
//處理下一條廣播
scheduleBroadcastsLocked();
if (anrMessage != null) {
// Post the ANR to the handler since we do not want to process ANRs while
// potentially holding our lock.
mHandler.post(new AppNotResponding(app, anrMessage));
}
}複製程式碼
所以當一個receiver超時後,系統會放棄繼續處理它給出ANR提示,並再次呼叫scheduleBroadcastsLocked(),嘗試處理下一個receiver,
private final class AppNotResponding implements Runnable {
private final ProcessRecord mApp;
private final String mAnnotation;
public AppNotResponding(ProcessRecord app, String annotation) {
mApp = app;
mAnnotation = annotation;
}
@Override
public void run() {
//內部建立ANR顯示的Dialog
mService.mAppErrors.appNotResponding(mApp, null, null, false, mAnnotation);
}
}複製程式碼
###4、廣播攔截處理分析
廣播訊息可以有多個接收者,對於有序廣播是一個接著一個處理的,優先順序高的接收者可以優先執行,並且可以呼叫BroadcastReceiver的abortBroadcast()方法攔截廣播,如果我們在receiver的onReceive()中呼叫這個方法,那麼它後面的接收者就不會收到廣播。
public abstract class BroadcastReceiver {
private PendingResult mPendingResult;
public final void abortBroadcast() {
checkSynchronousHint();
mPendingResult.mAbortBroadcast = true;
}
}複製程式碼
把BroadcastReceiver::PendingResult的成員變數mAbortBroadcast設定成true,
final class Args extends BroadcastReceiver.PendingResult implements Runnable {
private Intent mCurIntent;
private final boolean mOrdered;
private boolean mDispatched;
public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, int sendingUser) {
super(resultCode, resultData, resultExtras,
mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
mCurIntent = intent;
mOrdered = ordered;
}
public void run() {
.....
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
//設定PendingResult,這個PendingResult中mAbortBroadcast為true
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
} catch (Exception e) {
.....
}
if (receiver.getPendingResult() != null) {
//告知AMS處理下一個廣播
finish();
}
}
}複製程式碼
finish()會告知AMS處理下一個廣播,在第一小節已經分析過,最終進入AMS的finishReceiver方法
public void finishReceiver(IBinder who, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort, int flags) {
.....
try {
boolean doNext = false;
BroadcastRecord r;
synchronized(this) {
BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
? mFgBroadcastQueue : mBgBroadcastQueue;
r = queue.getMatchingOrderedReceiver(who);
if (r != null) {
//resultAbort傳進來是true,
doNext = r.queue.finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, true);
}
}
//呼叫processNextBroadcast處理廣播
if (doNext) {
r.queue.processNextBroadcast(false);
}
trimApplications();
} finally {
Binder.restoreCallingIdentity(origId);
}
}複製程式碼
processNextBroadcast方法中有一個檢查廣播有沒有傳送完畢的邏輯。
do {
.....
r = mOrderedBroadcasts.get(0);
//檢查廣播有沒有傳送完,resultAbort為=ture
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
.....
//mOrderedBroadcasts裡刪除廣播訊息
mOrderedBroadcasts.remove(0);
r = null;
looped = true;
continue;
}
} while (r == null);複製程式碼
當resultAbort為=ture時候,廣播訊息從mOrderedBroadcasts刪除,後面也就收不到廣播了。
###5、理解粘性廣播
sticky廣播通過Context.sendStickyBroadcast()函式來傳送,用此函式傳送的廣播會一直滯留,當有匹配此廣播的廣播接收器被註冊後,該廣播接收器就會收到此條資訊。使用此函式需要傳送廣播時,需要獲得BROADCAST_STICKY許可權。粘性廣播可以使用廣播接收器進行接收,但是正確的接收方式是呼叫registerReceiver能接受廣播,資訊將在呼叫registerReceiver的返回值中給出。對於粘性廣播的傳送,和普通廣播的傳送方式是一致的,例子來自與Android 粘性廣播StickyBroadcast的使用
private void sendStickyBroadcast(){
Intent i = new Intent();
i.setAction(StickyBroadcastReceiver.Action);
i.putExtra("info", "sticky broadcast has been receiver");
sendStickyBroadcast(i);
Log.i("Other","sticky broadcast send ok!");
}複製程式碼
可以使用BroadcastReceiver來接收
public class StickyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//收到廣播
}
}複製程式碼
<!--使用粘性廣播傳送許可權-->
<uses-permission android:name="android.permission.BROADCAST_STICKY" />複製程式碼
IntentFilter intentFilter = new IntentFilter(StickyBroadcastReceiver.Action);
Intent data = registerReceiver(null, intentFilter);
if(data!=null&&StickyBroadcastReceiver.Action.equals(data.getAction())) {
Toast.makeText(this, data.getStringExtra("info"), Toast.LENGTH_SHORT).show();
}複製程式碼
好了廣播的四篇文章寫完了,準備在分析一波Service吧