type
status
date
slug
summary
tags
category
icon
password
广播实现机制
先思考几个问题:
- 广播注册到了什么地方?
- 当发送广播的时候,是谁在分发广播?
- BroadcastReceiver是如何接收到广播的?
广播注册
从 Activity或者Context的
registerReceiver()
方法一路查看调用,可知最终注册实际上是在ActivityManagerService
里进行的.注册到了一个成员变量中:
final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
这里的ReceiverList实际上就是BroadcastFilter(IntentFilter的继承类)的ArrayList封装.
而IBinder则是
IItentReceiver
,是一个AIDL定义的接口,在 LoadedApk
的ReceiverDispatcher
中有相应的代理实现类IntentReceiver
.BroadcastReceiver
会被传递并封装到IItentReceiver
中.这样上面说的map其实也就清楚了: key ~= BroadcastReceiver, value ~= List<IntentFilter>
广播发送
从
sendBroadcast(Intent intent)
出发,最终依然是由ActivityManagerService#broadcastIntent()
方法处理的.这里大概几个步骤:
- 检查Intent对象合法性,是否有问题,然后封装一些中间类传递数据
- 检查Intent是否为一些系统级的广播ACTION,然后发出Handler消息做对应的处理
- sticky广播相关的逻辑
- 查询处理静态注册可以接收的reciever
- 通过IntentResolver查询符合要求的BroadcastFilter
- 获取对应的BroadcastQueue对象(有三种,前台,后台,卸载),并将对应的Intent封装到
BroadcastRecord
中,并添加到BroadcastQueue
中(queue.enqueueOrderedBroadcastLocked(r);
)
- 开始
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调用
IIntentReceiver
的performReceive()
方法去执行;正如前面所说,在
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); } } } } }
参考文章
- 作者:姜康
- 链接:https://jiangkang.tech/article/98c538c9-d64f-4f81-9460-c2b0d9ff8fb1
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章