浅谈Android中的Broadcast


![Android 广播](https://oss.jiangkang.tech/jk/Android 广播.png)

广播实现机制

先思考几个问题:

  • 广播注册到了什么地方?
  • 当发送广播的时候,是谁在分发广播?
  • BroadcastReceiver是如何接收到广播的?

广播注册

从 Activity或者Context的registerReceiver()方法一路查看调用,可知最终注册实际上是在ActivityManagerService里进行的.

注册到了一个成员变量中:

final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();

这里的ReceiverList实际上就是BroadcastFilter(IntentFilter的继承类)的ArrayList封装.

而IBinder则是IItentReceiver,是一个AIDL定义的接口,在 LoadedApkReceiverDispatcher中有相应的代理实现类IntentReceiver.

BroadcastReceiver会被传递并封装到IItentReceiver中.

这样上面说的map其实也就清楚了: key ~= BroadcastReceiver, value ~= List

广播发送

sendBroadcast(Intent intent)出发,最终依然是由ActivityManagerService#broadcastIntent()方法处理的.

这里大概几个步骤:

  1. 检查Intent对象合法性,是否有问题,然后封装一些中间类传递数据
  2. 检查Intent是否为一些系统级的广播ACTION,然后发出Handler消息做对应的处理
  3. sticky广播相关的逻辑
  4. 查询处理静态注册可以接收的reciever
  5. 通过IntentResolver查询符合要求的BroadcastFilter
  6. 获取对应的BroadcastQueue对象(有三种,前台,后台,卸载),并将对应的Intent封装到BroadcastRecord中,并添加到BroadcastQueue中(queue.enqueueOrderedBroadcastLocked(r);)
  7. 开始BroadcastQueue的调度,这里需要注意的是分为两种调度:
    • 并行: enqueueParallelBroadcastLocked(r)
    • 串行: enqueueOrderedBroadcastLocked(r)

广播分发/调度

BroadcastReceiver中有:

    public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        if (mBroadcastsScheduled) {
            return;
        }
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

    private final class BroadcastHandler extends Handler {
        public BroadcastHandler(Looper looper) {
            super(looper, null, true);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                // 接收调度消息
                case BROADCAST_INTENT_MSG: {
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
                            + mQueueName + "]");
                    // 此处是关键
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
            }
        }
    }

可以看到这里其实就是通过Handler Message机制进行调度的.

调度的逻辑里会区分当前进程是否已经正在运行,广播是串行还是并行的,然后进入各自的调度逻辑.

这里挑一个串行的调度逻辑分析下,并行的逻辑也是大同小异的.

串行分发逻辑最终都会通过oneway binder调用IIntentReceiverperformReceive()方法去执行;

正如前面所说,在LoadedApk.ReceiverDispathcer 中有:

        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            if (intent == null) {
                Log.wtf(TAG, "Null intent received");
            } else {
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                }
            }
            // intent一般不为null,因此会执行args中的runnbale
            if (intent == null || !mActivityThread.post(args.getRunnable())) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                }
            }
        }

getRunnable()方法中有:

                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        receiver.onReceive(mContext, intent);

                        ...

                        if (receiver.getPendingResult() != null) {
                           finish();
                        }

显而易见的,又是通过反射获取Receiver的对象并调用onReceive()方法.

执行完毕或者失败,发送执行完毕消息.

广播类型

  • 普通广播/有序广播/粘性广播

    普通广播随机顺序发送广播,有序广播串行发送数据,粘性广播不安全已被废弃

  • 串行/并行广播

    静态广播接收器不管广播是否为并行,都按照串行处理

    动态广播接收器遇到串行广播则按照串行处理,遇到并行广播则按照并行处理.

接收顺序问题

  • 广播发送时本身的优先级(比如有序广播)
  • 动态广播先于静态广播接收器收到广播

本地广播

主要是调用LocalBroadcastManager去使用,与系统广播的各种机制其实没什么关系,只是利用了一下BroadcastReceiver这个抽象类而已,其本质就是观察者模式 + Handler消息传递.因此在应用内传递效率颇高.

而且它的实现在支持包中,并不在源码中,目前是在androidx的支持包中.

看一段代码就明白了:

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);
                    }
                }
            }
        }
    }

参考文章

  1. https://developer.android.com/guide/components/broadcasts

文章作者: 姜康
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 姜康 !
评论
 上一篇
深入浅出Android中的事件分发机制 深入浅出Android中的事件分发机制
从输入硬件到Android窗口这里直接从底层硬件分析到事件传递到View的流程,具体的调用链查看源码,这里是基于Android 10 的源码分析的. 主要流程如下: 输入设备产生信号,比如手触摸屏幕,触摸屏产生电流或者电压信号,传递给设
2020-10-13
下一篇 
浅谈Android中的Handler 浅谈Android中的Handler
Handler.post(runnable) vs Handler.sendMessage(Message msg) public final boolean post(@NonNull Runnable r) { re
2020-10-06
  目录