要了解粘性广播,我们只需要简单地学习粘性广播用到的几个关键的类与结构
源码路径:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
只需要分析下广播的注册函数即可,因为我们知道粘性广播是在注册的时候马上返回的,下面的函数我只保留与粘性广播关键的部分
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
ArrayList<Intent> stickyIntents = null; //粘性广播
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {//mStickyBroadcasts保留着系统所有的粘性广播
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);
}
}
}
}
}
//到此为止stickyIntents是系统中所有的粘性的intent
ArrayList<Intent> allSticky = null;
if (stickyIntents != null) {
final ContentResolver resolver = mContext.getContentResolver();
// Look for any matching sticky broadcasts...
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
Intent intent = stickyIntents.get(i);
// If intent has scheme "content", it will need to acccess
// provider that needs to lock mProviderMap in ActivityThread
// and also it may need to wait application response, so we
// cannot lock ActivityManagerService here.
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList<Intent>();
}
allSticky.add(intent);
}
}
}
//allSticky就是与本次注册intentfilter匹配的粘性广播
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;
}
}
比较关键的数据结构是
1.mStickyBroadcasts,key是用户的id,data是广播intent数组。由此可见,粘性广播是分用户的,用户1发出的粘性广播,用户2可能收不到。
2.stickyIntents 保存的是系统所有粘性广播intent
3.allSticky 保存的是与本次registerReceiver(BroadcastReceiver receiver, IntentFilter intent)中intent匹配的粘性广播的intent
为了直观看到这三者,可以是用adb shell dumpsys activity -a 命令查看
Sticky broadcasts for user 0:
* Sticky action com.android.ims.IMS_SERVICE_DOWN:
Intent: act=com.android.ims.IMS_SERVICE_DOWN flg=0x20000010
Bundle[mParcelledData.dataSize=52]
* Sticky action com.example.stickybroadcastdemo.stickybrocast:
Intent: act=com.example.stickybroadcastdemo.stickybrocast flg=0x10
* Sticky action com.android.ims.IMS_SERVICE_UP:
Intent: act=com.android.ims.IMS_SERVICE_UP flg=0x20000010
Bundle[mParcelledData.dataSize=52]
* Sticky action com.google.android.apps.gmm.NAVIGATION_STATE:
Intent: act=com.google.android.apps.gmm.NAVIGATION_STATE flg=0x10 pkg=com.google.android.googlequicksearchbox
Bundle[mParcelledData.dataSize=248]
Intent: act=com.google.android.apps.gmm.NAVIGATION_STATE flg=0x10 pkg=com.google.android.gms
Bundle[mParcelledData.dataSize=248]
上面是user 0的粘性广播,其中的Sticky action com.example.stickybroadcastdemo.stickybrocast就是通过代码实现的
sendStickyBroadcast(new Intent("com.example.stickybroadcastdemo.stickybrocast")); //发送粘性广播