Android BroadcastReceiver的注册
2017-08-02 17:12
363 查看
广播接收器的注册
广播接收器,是用来接收系统和应用发出的广播,常见的是开机广播,可以用于实现开机启动服务的功能,还有网络变化,电池电量变化等等均会发出相应的广播。Android系统中的广播设计的很好,对于开发者而言非常容易上手。静态注册
不管该应用程序是否处于活动状态,都会进行监听,比如某个程序是监听内存的使用情况的,当在手机上安装好后,不管该应用程序是处于什么状态,都会执行该监听方法中的内容。静态注册即在AndroidManifest中注册广播接收器
//TODO 解释各个属性的意义
<receiver android:enabled=["true" | "false"] android:exported=["true" | "false"] android:icon="drawable resource" android:label="string resource" android:name="string" android:permission="string" android:process="string" > . . . </receiver>
实例:
<!-- AndroidManifest.xml --> <receiver android:name=".MyReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="MLY" /> </intent-filter> </receiver>
动态注册
在代码中进行注册后,当应用程序关闭后,就不再进行监听,因此一般在Activity创建的时候注册,在Activity销毁的时候取消注册。注册
IntentFilter filter = new IntentFilter(""); BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { } }; registerReceiver(receiver, filter);
取消注册
unregisterReceiver(receiver);
静态广播接收器的注册流程
Android系统启动后,PackageManagerService会扫描各个APK的AndroidManifest.xml,并解析其中的Receiver标签,最后将Receiver信息保存在PackageManagerService的receivers中。AMS就可以调用PMS的queryIntentReceivers函数获取到ResolveInfo列表,一个ResolveInfo代表一个BroadcastReceiver,AMS就可以通过ResolveInfo启动未启动的BroadcastReceiver所在的进程,然后将广播分发给静态注册的BroadcastReceiver。动态广播接收器注册流程
从序列图上看,动态广播的注册流程还是很简单的,在Activity里调用registerReceiver实际是调用了ComtextImpl的registerReceiver函数,该函数会调用registerReceiverInternal函数
Step 1
ComtextImpl.registerReceiverInternal该函数定义在frameworks/base/core/java/android/app/ContextImpl.java
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 { ...... } try { //调用了ActivityManagerNative的registerReceiver函数 return ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId); } catch (RemoteException e) { return null; } }
该函数主要是获取一个IIntentReceiver对象,最后AMS在分发广播的时候会通过这个对象回调到当前这个进程,一般情况下Receiver,mPackageInfo和context不为空,所以该对象是通过mPackageInfo.getReceiverDispatcher来获取的。同时scheduler指定了最后回调的函数运行的Handler,如果未指定,则是在主线程中。最后调用ActivityManagerNative的registerReceiver函数,该函数通过binder调用到AMS的registerReceiver。
Step 2
LoadedApk.getReceiverDispatcher函数该函数定义在frameworks/base/core/java/android/app/LoadedApk.java函数中
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); } } //一个BroadcastReceiver可以注册多次,如果是多次注册,这里的rd不为空,返回的IIntentReceiver也是相同的 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(); } }
registered参数表示是否是注册receiver函数调用。mReceivers是一个ArrayMap类型,key是Context,value也是ArrayMap类型,其中key是BroadcastReceiver,value是ReceiverDispatcher。
如果registered为true,函数首先会检查mReceivers是否已经注册了相同的BroadcastReceiver对象,如果是则直接返回该对象对应的ReceiverDispatcher中的IIntentReceiver。如果没有注册,则实例化一个ReceiverDispatcher对象,并将其加入到mReceivers中,然后其中的IIntentReceiver对象。
从这里可以看到一个BroadcastReceiver是可以注册多次的,这里可以指定不同的IntentFilter,但是每个BroadcastReceiver只能指定一个Handler。
如果registered为false,则直接实例化一个ReceiverDispatcher并返回,这里并不会将ReceiverDispatcher对象保存在mReceivers里。
Step 3
ActivityManagerService.registerReceiver该函数定义在frameworks/base/core/java/com/android/server/am/ActivityManagerService.java
synchronized (this) { ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); //同一个BroadcastReceiver第一次注册时,rl为null if (rl == null) { rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver); mRegisteredReceivers.put(receiver.asBinder(), rl); } else if (rl.uid != callingUid) { throw new IllegalArgumentException( "Receiver requested to register for uid " + callingUid + " was previously registered for uid " + rl.uid); } else if (rl.pid != callingPid) { throw new IllegalArgumentException( "Receiver requested to register for pid " + callingPid + " was previously registered for pid " + rl.pid); } else if (rl.userId != userId) { throw new IllegalArgumentException( "Receiver requested to register for user " + userId + " was previously registered for user " + rl.userId); } BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); rl.add(bf); mReceiverResolver.addFilter(bf); }
这里只截取主要的代码
1. 如果一个BroadcastReceiver是第一次注册,则rl为空,会实例化一个ReceiverList,该类型为ArrayList,用于保存同一个BroadcastReceiver注册的多个IntentFilter,然后将实例化ReceiverList和IIntentReceiver的binder对象保存mRegisteredReceivers Map中。
2. 如果非第一次注册,则会检查pid,uid,userId是否一致,若不一致则抛出异常
3. 实例化一个BroadcastFilter,并加入ReceiverList,同时会保存在mReceiverResolver中
至此,动态广播的注册结束。AMS中mReceiverResolver里包含了BroadcastFilter,这个与IntentFilter一一对应,BroadcastFilter里包含了IntentFilter和IIntentReceiver。 AMS中mRegisteredReceivers中,Key是IIntentReceiver的binder对象,Value是一个列表,包含了该对象对应的多个BroadcastFilter(与IntentFilter一一对应)。
动态广播接收器取消注册流程
Activity调用unregisterReceiver实际调用了ContextImpl的unregisterReceiver函数,该函数中调用LoadedApk的forgetReceiverDispatcher函数以及调用ActivityManagerNative的unregisterReceiver
Step 1
LoadedApk.forgetReceiverDispatcher该函数定义在frameworks/base/core/java/android/app/LoadedApk.java函数中
public IIntentReceiver forgetReceiverDispatcher(Context context, BroadcastReceiver r) { synchronized (mReceivers) { ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context); LoadedApk.ReceiverDispatcher rd = null; if (map != null) { rd = map.get(r); if (rd != null) { map.remove(r); if (map.size() == 0) { mReceivers.remove(context); } rd.mForgotten = true; return rd.getIIntentReceiver(); } } } }
该函数主要是将mReceivers中保存的BroadcastReceiver删除,并返回IIntentReceiver对象
Step 2
ActivityManagerService.unregisterReceiver该函数定义在frameworks/base/core/java/com/android/server/am/ActivityManagerService.java
public void unregisterReceiver(IIntentReceiver receiver) { final long origId = Binder.clearCallingIdentity(); try { boolean doTrim = false; synchronized(this) { ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl != null) { final BroadcastRecord r = rl.curBroadcast; if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) { final boolean doNext = r.queue.finishReceiverLocked( r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); if (doNext) { doTrim = true; r.queue.processNextBroadcast(false); } } if (rl.app != null) { rl.app.receivers.remove(rl); } removeReceiverLocked(rl); if (rl.linkedToDeath) { rl.linkedToDeath = false; rl.receiver.asBinder().unlinkToDeath(rl, 0); } } } } finally { Binder.restoreCallingIdentity(origId); } }
该函数首先判断接收器当前是否正在接收广播,若正在接收广播,需要处理finishReceiverLocked处理。然后调用removeReceiverLocked函数移除IIntentReceiver
Step 3
ActivityManagerService.removeReceiverLocked该函数定义在frameworks/base/core/java/com/android/server/am/ActivityManagerService.java
void removeReceiverLocked(ReceiverList rl) { mRegisteredReceivers.remove(rl.receiver.asBinder()); for (int i = rl.size() - 1; i >= 0; i--) { mReceiverResolver.removeFilter(rl.get(i)); } }
从前面动态广播的注册流程来看,当一个IIntentReceiver注册后,mRegisteredReceivers保存了IIntentReceiver对象及其所对应的BroadcastFilter列表。 mReceiverResolver会保存BroadcastFilter。因此这里取消注册时候,需要对应删除两个列表。
相关文章推荐
- Android开发学习笔记(3):BroadcastReceiver简介和注册方式
- Android BroadcastReceiver 的静态动态注册及区别
- Android(java)学习笔记173:BroadcastReceiver之 BroadcastReceiver静态注册(SD卡卸载或者安装案例)和 BroadcastReceiver动态注册注销
- Android LocalBroadcastManager 注册广播和直接registerReceiver的区别
- 关于Android中注册以内部类形式写的BroadcastReceiver的问题
- android BroadcastReceiver两种注册方式
- Android静态注册内部类广播BroadcastReceiver
- Android BroadcastReceiver注册方式比较
- Android:在AndroidManifest中注册BroadcastReceiver的权限问题
- Android开发22――广播接收者BroadcastReceiver的原理和注册
- Android-BroadcastReceiver注册方式
- Android开发学习笔记:BroadcastReceiver简介和注册方式
- Android 实时网路监测类 步骤一(NetWorkBroadcastReceiver 注册广播)
- Android BroadcastReceiver注册
- Android BroadcastReceiver两种注册方式区别
- Android:在AndroidManifest中注册BroadcastReceiver的权限问题
- android静态注册广播(BroadCastReceiver) Calling startActivity() from outside of an Activity
- Android Broadcast Receiver注册
- Android开发学习笔记:BroadcastReceiver简介和注册方式
- 【Android】BroadcastReceiver简介和用法实例,两种注册方式 (二)