Android源码解析四大组件系列(八)---广播几个问题的深入理解

接上篇文章,这篇文章主要是总结前面知识,并且了解一些细节问题,加深对广播机制的理解,比如有播有序是怎么保证有序的?广播拦截机制是怎么实现的?广播发送超时了是怎么处理的?registerReceiver方法发返回值有什么用?粘性广播等等。

Android源码解析四大组件系列(五)---广播的注册过程

Android源码解析四大组件系列(六)---广播的处理过程

Android源码解析四大组件系列(七)---广播的发送过程

1、广播相关数据结构的再次理解

  • ReceiverDispatcher: 客户端广播分发者对象,第一篇讲的很清楚了,ReceiverDispatcher的内部类InnerReceiver为binder对象,用于与AMS的传递与通信。

  • ReceiverList: 继承自ArrayList,存放了Receiver的binder对象以及其注册的BroadcastFilter列表。AMS中定义了
    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = 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吧

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容