Android BroadcastReceiver的注册
来源:互联网 发布:传奇霸业魔血符数据 编辑:程序博客网 时间:2024/05/21 10:42
广播接收器的注册
广播接收器,是用来接收系统和应用发出的广播,常见的是开机广播,可以用于实现开机启动服务的功能,还有网络变化,电池电量变化等等均会发出相应的广播。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 BroadcastReceiver的注册
- Android 注册BroadcastReceiver的两种方法
- Android 取消静态注册的BroadcastReceiver
- android BroadcastReceiver 注册方式
- Android BroadcastReceiver注册
- Android:动态注册BroadcastReceiver
- Android:静态注册BroadcastReceiver
- Android:静态注册BroadcastReceiver
- Android-BroadcastReceiver注册方式
- 注册BroadcastReceiver的方法
- android _ BroadcastReceiver 注册方式
- Android BroadcastReceiver注册方式比较
- android中broadcastreceiver的用法-manifest中注册。
- android中broadcastreceiver的用法-代码中注册
- Android:在AndroidManifest中注册BroadcastReceiver的权限问题
- Android注册BroadcastReceiver的两种办法及其区别
- Android BroadcastReceiver的注册方式静态和动态
- Android:在AndroidManifest中注册BroadcastReceiver的权限问题
- echarts实用篇(一)——饼状图
- 哈夫曼树(最优二叉树)
- 山东生第八届acm省赛 cf
- 数据库方法整合
- hdu1061 rightmost digit(C语言)
- Android BroadcastReceiver的注册
- 位、字节、字、kb的关系
- svg transform matrix
- 【转】升级nodejs版本
- 网络连接检测
- Java基础学习总结——Java对象的序列化和反序列化
- 扩展阅读 基于太极图对攻防进行建模
- <context:component-scan>使用说明
- 字符编码及其转换