Android 之 BroadcastReceiver 静态注册和动态注册 默认广播sendBroadcast(intent)
和有序广播sendOrderedBroadcast(intent)
在注册广播中的 中使用 android:priority 属性(-1000 ~ 1000,数值越大优先级越大);
动态注册广播不是常驻型广播,跟随 Activity 的生命周期。注意在 Activity 结束前,移除广播接收器。静态注册是常驻型,当应用关闭后,如有广播来,程序也会被系统调用自动运行;
当广播为有序广播时,优先级高的先接收(不分动态静态)。同优先级的广播接收器,动态优先于静态。
同优先级的同类广播接收器,静态:先扫描的优于后扫描的;动态:先注册的优于后注册的。
对于动态广播,有注册就必然得有注销,否则会导致内存泄漏
实现原理 Android 中的广播使用了设计模式中的观察者模式 :基于消息的发布/订阅事件模型。将广播的发送者和接收者极大程度解耦,使得系统能够方便集成,更易扩展。
自定义广播接收者 BroadcastReceiver,并重写 onReceiver()
方法;
通过 Binder 机制向 AMS (Activity Manager Service) 进行注册;
广播发送者通过 Binder 机制向 AMS 发送广播;
AMS 查找符合相应条件(IntentFilter/Permission 等)的 BroadcastReceiver,将广播发送到 BroadcastReceiver(一般情况下是 Activity)相应的消息循环队列中;
消息循环执行拿到此广播,回调 BroadcastReceiver 中的onReceive()
方法
底层实现原理 静态广播的注册 静态广播是通过 PackageManagerService 在启动的时候扫描已安装的应用去注册的。在其构造方法中,会去扫描应用的安装目录,顺序是先扫描系统应用安装目录在扫描第三方应用。用于扫描的方法PackageManagerService.scanDirLI()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private void scanDirLI (File dir, int flags, int scanMode, long currentTime) { String[] files = dir.list(); if (files == null ){ return ; } int i; for (i=0 ; i<files.length; i++){ File file = new File(dir, files[i]); if (!isPackageFilename(files[i])){ continue ; } PackageParser.Package pkg = scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null ); if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 && mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK){ file.delete(); } } } private static final boolean isPackageFilename (String name) { return name != null && name.endsWith(".apk" ); }
scanDirLI()
->scanPackageLI()
1 2 3 4 5 6 7 private PackageParser.Package scanPackageLI (File scanFile, int parseFlags, int scanMode, long currentTime, UserHandle user) { ... final PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags); ... PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user); ... }
scanDirLI()
->scanPackageLI()
->重载的scanPackageLI()
在这个scanPackageLI()
里面会解析 Package 并且将 AndroidManifest.xml 中注册的 BroadcastReceiver 保存下来
1 2 3 4 5 6 7 8 N = pkg.reveivers.size(); r = null ; for (i=0 ; i<N; i++){ PackageParser.Activity a = pkg.reveivers.get(i); a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mReceivers.addActivity(a, "receiver" ); ... }
可用PackageManagerService.queryIntentReceivers()
查询 intent 对应的静态广播。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public List<ResolveInfo> queryIntentReceivers (Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return Collections.emptyList(); ComponentName comp = intent.getComponent(); if (comp == null ){ if (intent.getSelector() != null ){ intent = intent.getSelector(); comp = intent.getComponent(); } } if (comp != null ){ List<ResolveInfo> list = new ArrayList<ResolveInfo>(1 ); ActivityInfo ai = getReceiverInfo(comp, flags, userId); if (ai != null ){ ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; list.add(ri); } return list; } synchronized (mPackages){ String pkgName = intent.getPackage(); if (pkgName == null ){ return mReceivers.queryIntent(intent, resolvedType, flags, userId); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null ){ return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers, userId); } return null ; } }
动态广播的注册 我们调用Context.registerReceiver()
最后都会调到ActivityManagerService.registerReceiver()
1 2 3 4 5 6 7 8 9 public Intent registerReceiver (IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { ... ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); ... BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); ... mReceiverResolver.addFilter(bf); ... }
所以通过mReceiverResolver.queryIntent()
就能获得 intent 对应的动态广播了。
发送广播 ContextImpl.sendBroadcast()
中会调用ActivityManagerNative.getDefault().broadcastIntent()
1 2 3 4 5 6 7 8 9 public void sendBroadcast (Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolvedTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null , Activity.RESULT_OK, null , null , null , AppOpsManager.OP_NONE, false , false , getUserId()); }catch (RemoteException e){ } }
实际上调用ActivityManagerService.broadcastIntent()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 public final int broadcastIntent (IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) { enforceNotIsolatedCaller("broadcastIntent" ); synchronized (this ){ intent = verifyBroadcastLocked(intent); final ProcessRecord callerApp = getRecordForAppLocked(caller); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); int res = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null , intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermission, appOp, serialized, sticky, callingPid, callingUid, userId); Binder.restoreCallingIdentity(origId); return res; } }
ActivityManagerService.broadcastIntent()
中又会调用ActivityManagerService.broadcastIntentLocked()
,其中关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 List receivers = null ; List<BroadcastFilter> registeredReceivers = null ; if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0 ){ receivers = collectReceiverComponents(intent, resolvedType, users); } if (intent.getComponent() == null ){ registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false , userId); } final boolean replacePending = (intent.getFlags() & Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0 ;int NR = registeredReceivers != null ? registeredReceivers.size() : 0 ;if (!ordered && NR > 0 ) { final BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermission, appOp, registeredReceivers, resultTo, resultCode, resultData, map, ordered, sticky, false , userId); final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r); if (!replaced) { queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } registeredReceivers = null ; NR = 0 ; } ... if ((receivers != null && receivers.size() > 0 ) || resultTo != null ) { BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermission, appOp, receivers, resultTo, resultCode, resultData, map, ordered, sticky, false , userId); boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); if (!replaced) { queue.enqueueOrderedBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } }
动态广播会优于静态广播,从上面的代码可以看到,这实际是因为 Android 的源代码就是按照这个顺序写的。
ActivityManagerService.collectReceiverComponents()
,实际上静态广播就是从 PackageManagerService 中查询的:
1 2 3 4 5 private List<ResolveInfo> collectReceiverComponents (Intent intent, String resolvedType, int [] users) { ... List<ResolveInfo> newReceivers = AppGlobals.getPackageManager().queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user); ... }
粘性广播的实现原理(API21已失效) ActivityManagerService.broadcastIntentLocked()
有下面这样一段代码,它将粘性广播存到了 mStickyBroadcasts 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 if (sticky){ ... ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); if (stickies == null ){ stickies = new ArrayMap<String, ArrayList<Intent>>(); mStickyBroadcasts.put(userId, stickies); } ArrayList<Intent> list = stickies.get(intent.getAction()); if (list == null ){ list = new ArrayList<Intent>(); stickies.put(intent.getAction(), list); } int N = list.size(); int i; for (i=0 ; i<N; i++) { if (intent.filterEquals(list.get(i))){ list.set(i, new Intent(intent)); break ; } } if (i >= N){ list.add(new Intent(intent)); } }
而 ManagerService.registerReceiver 会获取之前发送的粘性广播,再次发送给刚刚注册的 receiver:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 List allSticky = null ; Iterator actions = filter.actionsIterator(); if (actions != null ){ while (actions.hasNext()){ String action = (String)actions.next(); allSticky = getStickiesLocked(action, filter, allSticky, UserHandle.USER_ALL); allSticky = getStickiesLocked(action, filter, allSticky, UserHandle.getUserId (callingUid)); } }else { allSticky = getStickiesLocked(null , filter, allSticky, UserHandle.USER_ALL); allSticky = getStickiesLocked(null , filter, allSticky, UserHandle.getUserId(callingUid)); } ... if (allSticky != null ){ ArrayList receivers = new ArrayList(); receivers.add(bf); int N = allSticky.size(); for (int i=0 ; i<N; i++) { Intent intent = (Intent)allSticky.get(i); BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, null , null , -1 , -1 , null , null , AppOpsManager.OP_NONE, reveivers, null , 0 , null , null , false , true , true , -1 ); queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } } ...
getStickiesLocked()
即从 mStickyBroadcasts 中查询之前发送过的粘性广播
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private final List getStickiesLocked (String action, IntentFilter filter, List cur, int userId) { final ContentResolver resolver = mContext.getContentResolver(); ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); if (stickies == null ){ return cur; } final ArrayList<Intent> list = stickies.get(action); if (list == null ){ return cur; } int N = list.size(); for (int i=0 ; i<N; i++) { Intent intent = list.get(i); if (filter.match(resolver, intent, true , TAG) >= 0 ){ if (cur == null ){ cur = new ArrayList<Intent>(); } cur.add(intent); } } return cur; }
广播队列 从ActivityManagerService.broadcastIntentLocked()
可以看到,实际上它不是直接将广播发送到 BroadcastReceiver 中的,而是将它包装到 BroadcastRecord 中,再放进 BroadcastQueue:
1 2 3 4 5 6 BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, null , null , -1 , -1 , null , null , AppOpsManager.OP_NONE, receivers, null , 0 , null , null , false , true , true , -1 ); queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked();
enqueueParallelBroadcastLocked()
方法用于并发执行广播的发送:
1 2 3 public void enqueueParallelBroadcastLocked (BroadcastRecord r) { mParallelBroadcasts.add(r); }
scheduleBroadcastsLocked()
就是向 mHandler 发送了个 BROADCAST_INTENT_MSG 消息:
1 2 3 4 5 6 7 public void scheduleBroadcastsLocked () { if (mBroadcastsScheduled){ return ; } mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this )); mBroadcastsScheduled = true ; }
mHandler 的工作:
1 2 3 4 5 6 7 8 9 10 final Handler mHandler = new Handler(){ public void handleMessage (Message msg) { case BROADCAST_INTENT_MSG:{ processNextBroadcast(true ); } break ; case BROADCAST_TIMEOUT_MSG:{ broadcastTimeoutLocked(true ); } break ; } }
processNextBroadcast()
用于从队列中获取广播消息并发给 BroadcastReceiver,它内部有两个分支,并行处理和串行处理:
并行处理:例如动态注册的非有序广播等就是使用并行处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 final void processNextBroadcast (boolean fromMsg) { synchronized (mService){ BroadcastRecord r; mService.updateCpuStats(); if (fromMsg){ mBroadcastsScheduled = false ; } while (mParallelBroadcasts.size() > 0 ){ r = mParallelBroadcasts.remove(0 ); r.dispatchTime = SystemClock.currentTimeMills(); final N = r.receivers.size(); for (int i=0 ; i<N; i++) { Object target = r.reveivers.get(i); deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false ); } addBroadcastToHistoryLocked(r); } ... } ... } private final void deliverToRegisteredReceiverLocked (BroadcastRecord r, BroadcastFilter filter, boolean ordered) { ... r.receiver = filter.receiverList.receiver.asBinder(); ... performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.initialSticky, r.userId); ... } void performReceiveLocked (ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException { ... app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, ordered, sticky, sendingUser, app.repProcState); ... }
串行处理:例如有序广播和静态广播,会通过enqueueOrderedBroadcastLocked()
传给 BroadcastQueue:
1 2 3 public void enqueueOrderedBroadcastLocked (BroadcastRecord r) { mOrderedBroadcasts.add(r); }
然后在processNextBroadcast()
里面会对 mOrderedBroadcasts 进行特殊处理… (我也看不懂啊~)
总结 广播队列传送广播给 Receiver 的原理其实就是将 BroadcastReceiver 和消息都放到 BroadcastRecord 里面,然后通过 Handler 机制遍历 BroadcastQueue 里面的 BroadcastRecord,将消息发送给 BroadcastReceiver。
整个广播机制可以总结成下面这张图:
参考引用 Android 广播Broadcast的两种注册方式静态和动态 特别感谢 安卓广播的底层实现原理 ,其实很多都是照着打,还得慢慢看
v1.5.2