1, 基本概念
广播(Broadcast):顾名思义,就是一处发生事情,多处得到通知后分别进行处理。和观察者模式有相似之处。一般Activity发送广播。
1.1 receiver
receiver接收广播,还分为动态和静态两种。动态receiver是在运行期通过调用registerReceiver()注册的,而静态receiver则是在
AndroidManifest.xml中声明的。一般使用动态广播,原因可以研究一下。有事广播已经发出去了,包含接受静态广播的进程还没
有起来,因为在手机开机时注册。比如,刚开机时,phone进程还没有开始运行,别人就已经打电话来了,这时候先运行phone进程,
然后在进程里接收广播并进行处理。
1.2 Broadcast
依据Broadcast的作用,可以将广播分为三种:
1,一般广播,所有注册该广播的receiver都处于相同的位置,同时接受并且处理。
2,有序广播,所有receiver只能按照一定的优先级顺序,依次接收并且处理;不仅如此,前面的receiver不仅可以将额外的信息
塞入广播还可以终止广播。
静态广播: AndroidManifest.xml, <intent-filter>android:priority属性
动态广播: IntentFilter对象的setPriority()方法来设置优先级
数值越大表示优先级越高,取值范围为-1000到1000.
3,粘性广播: 可以保证“在广播递送时尚未注册的receiver”,一旦日后注册进系统,就能够马上接到“错过”的sticky广播。
这是一种很神奇的广播,我觉得关机时的来电(开机后,收到错过电话的通知)应该就是这种广播。
静态广播大都是有序广播。
2,注册广播关键代码解析
2.1 类图
2.2 流程图
动态广播注册的流程图如下,
2.3 代码解析
ContextImpl的registerReceiver方法如下,
首先看看getReceiverDispatcher方法,
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext());
}
registerReceiverInternal方法如下,
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
}
getReceiverDispatcher方法如下,
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
if (rd == null) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
看mReceivers的定义,是一个表中表,
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>>
mReceivers = new ArrayMap<Context, ArrayMap<BroadcastReceiver,
LoadedApk.ReceiverDispatcher>>();
在Android的架构里,应用进程里是用LoadedApk来对应一个apk的,进程里加载了多少个apk,就会有多少LoadedApk。
每个LoadedApk里会有一张“关于本apk动态注册的所有receiver”的哈希表mReceivers。该表的key项是我们比较熟悉的
Context,也就是说可以是Activity、Service或Application。而value项则是另一张“子哈希表”。这是个“表中表”的形式。
言下之意就是,每个Context(比如一个activity),是可以注册多个receiver的,这个很好理解。mReceivers里的“
子哈希表”的key值为BroadcastReceiver,value项为ReceiverDispatcher,示意图如下:
然后看看跨进程调用到AMS中的registerReceiver方法,
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
enforceNotIsolatedCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
int callingUid;
int callingPid;
synchronized(this) {
•••
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
if (stickies != null) {
ArrayList<Intent> intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList<Intent>();
}
stickyIntents.addAll(intents);
}
}
}
}
}
synchronized (this) {
•••
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
rl.app.receivers.add(rl);
} else {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
•••
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);
if (allSticky != null) {
ArrayList receivers = new ArrayList();
receivers.add(bf);
final int stickyCount = allSticky.size();
for (int i = 0; i < stickyCount; i++) {
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
注意这句 mReceiverResolver . addFilter (bf);后面动态广播查询的时候会调用此查询。
registerReceiver()函数的filter参数指明了用户对哪些intent感兴趣。对同一个BroadcastReceiver对象来说,可以注册
多个感兴趣的filter,就好像声明静态receiver时,也可以为一个receiver编写多个<intent-filter>一样。这些IntentFilter信息
会汇总到AMS的mRegisteredReceivers表中。每个客户端的ReceiverDispatcher,会对应AMS端的一个ReceiverList。
将上文的ReceiverDispatcher和ReceiverList通过mRegisteredReceivers一一对应。
138.final HashMap<IBinder,ReceiverList> mRegisteredReceivers= new HashMap<>();
一个receiver可以包含多个不同的IntentFilter,可以被Context注册多次。因此
ReceiverList里面保存的是相同receiver的不同IntentFilter(过滤器)。所以最终的对应关系为
2.4 静态receiver
静态receiver是在AndroidManifest.xml文件中声明,该信息会在系统启动时,由PackageManagerService解析并记录下来。
静态receiver并不是是常驻内存的,常驻内存的只是静态receiver的描述性信息,并不是receiver实体本身。
该类向外界提供了queryIntentReceivers()函数,该函数可以返回一个List<ResolveInfo>列表。主要目的就是当系统发出一个
广播时,该类必须能够得出有多少静态receiver对这个广播感兴趣,而且知道这些receiver的详细信息。