Android源码解析四大组件系列(八)---广播几个问题的深入理解
2017-07-24 15:29
1191 查看
接上篇文章,这篇文章主要是总结前面知识,并且了解一些细节问题,加深对广播机制的理解,比如有播有序是怎么保证有序的?广播拦截机制是怎么实现的?广播发送超时了是怎么处理的?registerReceiver方法发返回值有什么用?粘性广播等等。
Android源码解析四大组件系列(五)—广播的注册过程
Android源码解析四大组件系列(六)—广播的处理过程
Android源码解析四大组件系列(七)—广播的发送过程
ReceiverList: 继承自ArrayList,存放了Receiver的binder对象以及其注册的BroadcastFilter列表。AMS中定义了
final HashMap
因为在调用onReceive之前,执行了 receiver.setPendingResult(this),所以在下面receiver.getPendingResult()就不是null,则就进入BroadcastReceiver的内部类PendingResult的finish方法。
finish方法中根据mType的值有两个分支。mType是PendingResult的成员变量,在PendingResult的构造函数中进行赋值的。
这个构造方法是在BroadcastReceiver.PendingResult的子类Args中调用的
由于mRegistered是动态注册广播接收者传进来的,值是true,所以上面mType的值是TYPE_REGISTERED,由于是有序广播ordered值是true,那么mOrderedHint为true,所以要走第二个分支:
BroadcastReceiver的sendFinished方法如下:
有序广播mOrderedHint值为true,所以进入到AMS的finishReceiver方法。
上面是分析了动态的广播接收者是怎么按照一个接着一个处理的。在看看静态注册的receiver,回到静态广播回调onReceive方法的地方。
在回调onReceiver方法之前, 执行了 receiver.setPendingResult(data),所以下面receiver.getPendingResult() != null成立,走 data.finish(),data是ReceiverData对象,handleReceiver方法传进来的,在scheduleReceiver方法中初始化。
我们看 data.finish()方法
此时mType分析后值是TYPE_COMPONENT,同样会走sendFinished,后面AMS的处理逻辑是一样的,不赘述。
在processNextBroadcast方法中有下面一段代码,与广播超时有关系,一旦超时就会出现ANR。
广播的超时机制是针对有序广播来说的,无序广播一次性全部处理了,肯定不会超时,超时的这段逻辑都在broadcastTimeoutLocked中,首先判断是否超时,公式:r.dispatchTime + 2×mTimeoutPeriod×numReceivers,现在解释一下这几个时间:
- dispatchTime的意义是标记实际处理BroadcastRecord的起始时间,有序广播是一个接着一个进行处理的,第一次dispatchTime=0,并不会进入该条件判断
mTimeoutPeriod由当前BroadcastQueue的类型决定(mFgBroadcastQueue为10秒,mBgBroadcastQueue为60秒)
所以上面公式翻译过来就是:实际处理BroadcastRecord的起始时间+广播默认的超时时间*广播接收者的数量。话说回来,这个公式为什么要这么设计呢?如果一个前台的广播消息有两个接收者,那么在20秒(2 x 10)之内搞定就可以了,也可能第一个消息执行了15秒,第二个消息执行4.99秒,即使第一消息超过了10秒的规定,也不会出现ANR。但是系统任务繁忙,可能有其他活要干,我们要尽可能的减少ANR的发生,所以前面乘以2倍。
假设现在广播超时还没处理,满足if条件,就会进入,打印Hung broadcast [“+ mQueueName + “] discarded after timeout failure….的log,然后执行 broadcastTimeoutLocked(false)强制停止广播,broadcastTimeoutLocked相关代码代码如下:
内部调用setBroadcastTimeoutLocked()设置一个延迟消息
如果广播消息能够处理完毕,就会执行cancelBroadcastTimeoutLocked,将超时的Message移除掉。
如果广播消息没有在timeout时间内处理掉,下面BroadcastHandler发送的消息就会执行。
再次进入broadcastTimeoutLocked方法里面
所以当一个receiver超时后,系统会放弃继续处理它给出ANR提示,并再次调用scheduleBroadcastsLocked(),尝试处理下一个receiver,
把BroadcastReceiver::PendingResult的成员变量mAbortBroadcast设置成true,
finish()会告知AMS处理下一个广播,在第一小节已经分析过,最终进入AMS的finishReceiver方法
当resultAbort为=ture时候,广播消息从mOrderedBroadcasts删除,后面也就收不到广播了。
可以使用BroadcastReceiver来接收
好了广播的四篇文章写完了,准备在分析一波Service吧
Android源码解析四大组件系列(五)—广播的注册过程
Android源码解析四大组件系列(六)—广播的处理过程
Android源码解析四大组件系列(七)—广播的发送过程
1、广播相关数据结构的再次理解
ReceiverDispatcher: 客户端广播分发者对象,第一篇讲的很清楚了,ReceiverDispatcher的内部类InnerReceiver为binder对象,用于与AMS的传递与通信。ReceiverList: 继承自ArrayList,存放了Receiver的binder对象以及其注册的BroadcastFilter列表。AMS中定义了
final HashMap
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吧
相关文章推荐
- Android源码解析四大组件系列(七)---广播的发送过程
- Android源码解析四大组件系列(五)---广播的注册过程
- Android源码解析四大组件系列(六)---广播的处理过程
- Android源码解析四大组件系列(一)---Service的启动过程分析
- Android源码解析四大组件系列(四)---Activity启动详细流程
- Android源码解析四大组件系列(二)---Activity启动过程的总体把握
- Android源码解析四大组件系列(三)---Activity启动过程之ActivityThread是如何运行起来的
- Android EventBus源码解析 带你深入理解EventBus
- Android源码系列之深入理解ImageView的ScaleType属性
- Android EventBus源码解析 带你深入理解EventBus
- 深入理解Android四大组件之一BroadcastReceiver
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- (4.2.10.3)【android开源组件】Android Volley完全解析(四),带你从源码的角度理解Volley
- Android 源码系列之<七>从源码的角度深入理解IntentService及HandlerThread
- Android 源码系列之<五>从源码的角度深入理解LayoutInflater.Factory之主题切换(中)
- Android EventBus源码解析 带你深入理解EventBus
- Android 源码系列之<四>从源码的角度深入理解LayoutInflater.Factory之主题切换(上)
- Android 源码系列之<三>从安全的角度深入理解BroadcastReceiver(下)