BroadcastReceiver详细分析之串行广播的调度和超时机制

上一篇文章我们主要梳理了广播的动态注册,发送,接收,主要的数据结构以及需要大家严重注意的几点内容,相信大家已经熟悉了。没看过的朋友传送门:BroadcastReceiver详细分析之主要流程

相信聪明的朋友已经发现,上篇基本没怎么介绍串行广播和静态注册器,基本介绍的是普通广播的动态注册器的流程。因此,本篇单独讲解串行广播以及静态注册器的相关调度以及超时机制,毕竟这块知识点还是很多的,值得单开一篇文章。

本篇代码仍然基于原生Android Q

一.有序广播的基本使用

BroadcastReceiver的注册、发送和接收的主要流程和核心数据结构都已经讲解完。本篇主要讲述有序广播的调度和超时,无序广播都是并行发送的,不存在优先级和回调机制,因此也不会存在超时机制。这个好理解吧?还是再提一下吧,无序广播的动态注册器接收在上篇中都是循环直接发送的,属于binder的one way调用,AMS不需要等待它们执行结果。而有序广播需要根据接收器的优先级一个个发送,优先级高的接收器可以拦截广播等等,既然有先来后到,那么咱就只能一个个发了,并且前面的接收器要是处理时间太长怎么办?这不是影响后面的接收器了嘛,因此肯定会有超时机制。OK,废话不多说,我们开始:

下面是有序广播的基本使用方法:

//定义广播
BroadcastReceiver receiver=new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(MainActivity.this,"这是xiaomiapp2",Toast.LENGTH_LONG).show();
    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    IntentFilter intentFilter=new IntentFilter("a.b.c");
    registerReceiver(receiver,intentFilter);            //注册广播
 
    ......
    Intent intent=new Intent();                         //发送广播
    intent.setAction("a.b.c");
    sendOrderedBroadcast(intent,null);

平平无奇的代码,不需要过多说。

二.串行广播的调度过程

根据之前介绍,串行广播是将动态注册和静态注册的接收器根据优先级合并在一起,然后统一调度。无序广播都是one way binder call,因此发完就发完了,不存在通知AMS,而有序广播发完是需要通知AMS的,因此需要一个一个的来,让我们回到BroadcastQueue的processNextBroadcastLocked方法:

    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        BroadcastRecord r;

        //......无序动态广播的处理,不再赘述

        // Now take care of the next serialized one...

        

        boolean looped = false;

        do {
            final long now = SystemClock.uptimeMillis();
            //取出有序广播一个BroadcastRecord任务
            r = mDispatcher.getNextBroadcastLocked(now); 

            if (r == null) {  //没有更多任务了
                // No more broadcasts are deliverable right now, so all done!
                mDispatcher.scheduleDeferralCheckLocked(false);
                mService.scheduleAppGcsLocked();
                if (looped) {
                    // If we had finished the last ordered broadcast, then
                    // make sure all processes have correct oom and sched
                    // adjustments.
                    mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
                }

                // when we have no more ordered broadcast on this queue, stop logging
                if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {
                    mLogLatencyMetrics = false;
                }

                return;
            }

            boolean forceReceive = false;

            // Ensure that even if something goes awry with the timeout
            // detection, we catch "hung" broadcasts here, discard them,
            // and continue to make progress.
            //
            // This is only done if the system is ready so that early-stage receivers
            // don't get executed with timeouts; and of course other timeout-
            // exempt broadcasts are ignored.
            //取出广播任务包含的所有接收器数量
            int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
           
          //......

        // Get the next receiver...
        int recIdx = r.nextReceiver++; //取出该任务中的下一个接收器

        //......

        final BroadcastOptions brOptions = r.options;
        final Object nextReceiver = r.receivers.get(recIdx);

        //有序广播中的动态注册的广播,动态注册的广播是BroadcastFilter实例,静态注册的是ResolveInfo实例
        if (nextReceiver instanceof BroadcastFilter) {
            // Simple case: this is a registered receiver who gets
            // a direct call.
            BroadcastFilter filter = (BroadcastFilter)nextReceiver;
            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                    "Delivering ordered ["
                    + mQueueName + "] to registered "
                    + filter + ": " + r);
            //同样调用deliverToRegisteredReceiverLocked方法
            deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
            if (r.receiver == null || !r.ordered) {
                // The receiver has already finished, so schedule to
                // process the next one.
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
                        + mQueueName + "]: ordered="
                        + r.ordered + " receiver=" + r.receiver);
                r.state = BroadcastRecord.IDLE;
                scheduleBroadcastsLocked();
            } else {
                if (filter.receiverList != null) {
                    maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
                    // r is guaranteed ordered at this point, so we know finishReceiverLocked()
                    // will get a callback and handle the activity start token lifecycle.
                }
                if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                    scheduleTempWhitelistLocked(filter.owningUid,
                            brOptions.getTemporaryAppWhitelistDuration(), r);
                }
            }
            return;
        }

        // Hard case: need to instantiate the receiver, possibly
        // starting its application process to host it.

        ResolveInfo info =
            (ResolveInfo)nextReceiver;
        ComponentName component = new ComponentName(
                info.activityInfo.applicationInfo.packageName,
                info.activityInfo.name);

        boolean skip = false;
        
        //......关于广播是否跳过的一系列判断
        
        r.manifestCount++;

        r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
        r.state = BroadcastRecord.APP_RECEIVE;
        r.curComponent = component;
        r.curReceiver = info.activityInfo;
        if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
            Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
                    + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
                    + receiverUid);
        }

        if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
            scheduleTempWhitelistLocked(receiverUid,
                    brOptions.getTemporaryAppWhitelistDuration(), r);
        }

        // Broadcast is being executed, its package can't be stopped.
        try {
            AppGlobals.getPackageManager().setPackageStoppedState(
                    r.curComponent.getPackageName(), false, r.userId);
        } catch (RemoteException e) {
        } catch (IllegalArgumentException e) {
            Slog.w(TAG, "Failed trying to unstop package "
                    + r.curComponent.getPackageName() + ": " + e);
        }

        // Is this receiver's application already running?
        //判断接收器进程是否存在,存在才会执行,这里适用于静态注册的广播
        if (app != null && app.thread != null && !app.killed) {
            try {
                app.addPackage(info.activityInfo.packageName,
                        info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
                maybeAddAllowBackgroundActivityStartsToken(app, r);
                processCurBroadcastLocked(r, app, skipOomAdj); //处理静态注册的有序广播
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when sending broadcast to "
                      + r.curComponent, e);
            } catch (RuntimeException e) {
                Slog.wtf(TAG, "Failed sending broadcast to "
                        + r.curComponent + " with " + r.intent, e);
                // If some unexpected exception happened, just skip
                // this broadcast.  At this point we are not in the call
                // from a client, so throwing an exception out from here
                // will crash the entire system instead of just whoever
                // sent the broadcast.
                logBroadcastReceiverDiscardLocked(r);
                finishReceiverLocked(r, r.resultCode, r.resultData,
                        r.resultExtras, r.resultAbort, false);
                scheduleBroadcastsLocked();
                // We need to reset the state if we failed to start the receiver.
                r.state = BroadcastRecord.IDLE;
                return;
            }

            // If a dead object exception was thrown -- fall through to
            // restart the application.
        }

        // Not runn
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
安卓的BroadcastReceiver可以被用来接收系统发送的广播消息,而AlarmManager则可以用来触发在特定时间触发的定时任务。然而,在某些情况下,我们可能会遇到AlarmManager无法将广播发送给BroadcastReceiver的问题。 出现这种情况的原因可能有多个。一种可能性是未正确注册BroadcastReceiver。在AndroidManifest.xml文件中,需要添加正确的intent-filter来指定BroadcastReceiver接收的广播类型。如果没有正确添加intent-filter,那么AlarmManager发送的广播就无法被BroadcastReceiver接收到。 另一种可能性是未正确设置AlarmManager的PendingIntent。在设置AlarmManager时,我们需要为PendingIntent指定BroadcastReceiver的类。如果未正确设置PendingIntent,那么AlarmManager发送的广播就无法正确地被指定的BroadcastReceiver接收到。 此外,还有可能是由于权限问题导致BroadcastReceiver无法接收AlarmManager发送的广播。当AlarmManager发送广播时,需要确保应用程序具有相应的权限。如果没有正确配置权限,那么BroadcastReceiver将无法接收到AlarmManager发送的广播。 解决这个问题的步骤包括: 1. 在AndroidManifest.xml文件中确保正确注册BroadcastReceiver,并添加正确的intent-filter。 2. 在设置AlarmManager时,确保为PendingIntent正确指定BroadcastReceiver的类。 3. 确认应用程序具有相应的权限来接收AlarmManager发送的广播。 通过以上步骤的检查和调整,应该能够解决AndroidBroadcastReceiver收不到AlarmManager发送的广播的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值