Android应用程序注册广播接收器(registerReceiver)的过.docx_第1页
Android应用程序注册广播接收器(registerReceiver)的过.docx_第2页
Android应用程序注册广播接收器(registerReceiver)的过.docx_第3页
Android应用程序注册广播接收器(registerReceiver)的过.docx_第4页
Android应用程序注册广播接收器(registerReceiver)的过.docx_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

前面我们介绍了Android系统的广播机制,从本质来说,它是一种消息订阅/发布机制,因此,使用这种消息驱动模型的第一步便是订阅消息;而对Android应用程序来说,订阅消息其实就是注册广播接收器,本文将探讨Android应用程序是如何注册广播接收器以及把广播接收器注册到哪里去的。 在Android的广播机制中,ActivityManagerService扮演着广播中心的角色,负责系统中所有广播的注册和发布操作,因此,Android应用程序注册广播接收器的过程就把是广播接收器注册到ActivityManagerService的过程。Android应用程序是通过调用ContextWrapper类的registerReceiver函数来把广播接收器BroadcastReceiver注册到ActivityManagerService中去的,而ContextWrapper类本身又借助ContextImpl类来注册广播接收器。 在Android应用程序框架中,Activity和Service类都继承了ContextWrapper类,因此,我们可以在Activity或者Service的子类中调用registerReceiver函数来注册广播接收器。Activity、Service、ContextWrapper和ContextImpl这四个类的关系可以参考前面Android系统在新进程中启动自定义服务过程(startService)的原理分析一文中描述的Activity类图。 这篇文章还是继续以实例来进行情景分析,所用到的例子便是上一篇文章Android系统中的广播(Broadcast)机制简要介绍和学习计划里面介绍的应用程序了,所以希望读者在继续阅读本文之前,先看看这篇文章;又由于Android应用程序是把广播接器注册到ActivityManagerService中去的,因此,这里又会涉入到Binder进程间通信机制,所以希望读者对Android系统的Binder进程间通信机制有所了解,具体请参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。 开始进入主题了,在Android系统中的广播(Broadcast)机制简要介绍和学习计划一文所介绍的例子中,注册广播接收器的操作是MainActivity发起的,我们先来看看注册过程的序列图: 在分析这个序列图之前,我们先来看一下MainActivity是如何调用registerReceiver函数来注册广播接收器的:view plain1. publicclassMainActivityextendsActivityimplementsOnClickListener2. .3. 4. Override5. publicvoidonResume()6. super.onResume();7. 8. IntentFiltercounterActionFilter=newIntentFilter(CounterService.BROADCAST_COUNTER_ACTION);9. registerReceiver(counterActionReceiver,counterActionFilter);10. 11. 12. .13. 14. MainActivity在onResume函数里,通过其父类ContextWrapper的registerReceiver函数注册了一个BroadcastReceiver实例counterActionReceiver,并且通过IntentFilter实例counterActionFilter告诉ActivityManagerService,它要订阅的广播是CounterService.BROADCAST_COUNTER_ACTION类型的,这样,ActivityManagerService在收到CounterService.BROADCAST_COUNTER_ACTION类型的广播时,就会分发给counterActionReceiver实例的onReceive函数。 接下来,就开始分析注册过程中的每一个步骤了。 Step 1. ContextWrapper.registerReceiver 这个函数实现在frameworks/base/core/java/android/content/ContextWrapper.java文件中:view plain1. publicclassContextWrapperextendsContext2. ContextmBase;3. .4. 5. Override6. publicIntentregisterReceiver(7. BroadcastReceiverreceiver,IntentFilterfilter)8. returnmBase.registerReceiver(receiver,filter);9. 10. 11. .12. 13. 这里的成员变量mBase是一个ContextImpl实例,想知道为什么,可以回过头去看看Android应用程序启动过程源代码分析这篇文章。 Step 2. ContextImpl.registerReceiver 这个函数实现在frameworks/base/core/java/android/app/ContextImpl.java文件中:view plain1. classContextImplextendsContext2. .3. 4. Override5. publicIntentregisterReceiver(BroadcastReceiverreceiver,IntentFilterfilter)6. returnregisterReceiver(receiver,filter,null,null);7. 8. 9. Override10. publicIntentregisterReceiver(BroadcastReceiverreceiver,IntentFilterfilter,11. StringbroadcastPermission,Handlerscheduler)12. returnregisterReceiverInternal(receiver,filter,broadcastPermission,13. scheduler,getOuterContext();14. 15. 16. privateIntentregisterReceiverInternal(BroadcastReceiverreceiver,17. IntentFilterfilter,StringbroadcastPermission,18. Handlerscheduler,Contextcontext)19. IIntentReceiverrd=null;20. if(receiver!=null)21. if(mPackageInfo!=null&context!=null)22. if(scheduler=null)23. scheduler=mMainThread.getHandler();24. 25. rd=mPackageInfo.getReceiverDispatcher(26. receiver,context,scheduler,27. mMainThread.getInstrumentation(),true);28. else29. .30. 31. 32. try33. returnActivityManagerNative.getDefault().registerReceiver(34. mMainThread.getApplicationThread(),35. rd,filter,broadcastPermission);36. catch(RemoteExceptione)37. returnnull;38. 39. 40. 41. .42. 43. 通过两个函数的中转,最终就进入到ContextImpl.registerReceiverInternal这个函数来了。这里的成员变量mPackageInfo是一个LoadedApk实例,它是用来负责处理广播的接收的,在后面一篇文章讲到广播的发送时(sendBroadcast),会详细描述。参数broadcastPermission和scheduler都为null,而参数context是上面的函数通过调用函数getOuterContext得到的,这里它就是指向MainActivity了,因为MainActivity是继承于Context类的,因此,这里用Context类型来引用。 由于条件mPackageInfo != null和context != null都成立,而且条件scheduler = null也成立,于是就调用mMainThread.getHandler来获得一个Handler了,这个Hanlder是后面用来分发ActivityManagerService发送过的广播用的。这里的成员变量mMainThread是一个ActivityThread实例,在前面Android应用程序启动过程源代码分析这篇文章也描述过了。我们先来看看ActivityThread.getHandler函数的实现,然后再回过头来继续分析ContextImpl.registerReceiverInternal函数。 Step 3. ActivityThread.getHandler 这个函数实现在frameworks/base/core/java/android/app/ActivityThread.java文件中:view plain1. publicfinalclassActivityThread2. .3. 4. finalHmH=newH();5. 6. privatefinalclassHextendsHandler7. .8. 9. publicvoidhandleMessage(Messagemsg)10. .11. 12. switch(msg.what)13. .14. 15. 16. .17. 18. 19. .20. 21. 22. 23. .24. 25. finalHandlergetHandler()26. returnmH;27. 28. 29. .30. 31. 有了这个Handler之后,就可以分发消息给应用程序处理了。 再回到上一步的ContextImpl.registerReceiverInternal函数中,它通过mPackageInfo.getReceiverDispatcher函数获得一个IIntentReceiver接口对象rd,这是一个Binder对象,接下来会把它传给ActivityManagerService,ActivityManagerService在收到相应的广播时,就是通过这个Binder对象来通知MainActivity来接收的。 我们也是先来看一下mPackageInfo.getReceiverDispatcher函数的实现,然后再回过头来继续分析ContextImpl.registerReceiverInternal函数。 Step 4. LoadedApk.getReceiverDispatcher 这个函数实现在frameworks/base/core/java/android/app/LoadedApk.java文件中:view plain1. finalclassLoadedApk2. .3. 4. publicIIntentReceivergetReceiverDispatcher(BroadcastReceiverr,5. Contextcontext,Handlerhandler,6. Instrumentationinstrumentation,booleanregistered)7. synchronized(mReceivers)8. LoadedApk.ReceiverDispatcherrd=null;9. HashMapmap=null;10. if(registered)11. map=mReceivers.get(context);12. if(map!=null)13. rd=map.get(r);14. 15. 16. if(rd=null)17. rd=newReceiverDispatcher(r,context,handler,18. instrumentation,registered);19. if(registered)20. if(map=null)21. map=newHashMap();22. mReceivers.put(context,map);23. 24. map.put(r,rd);25. 26. else27. rd.validate(context,handler);28. 29. returnrd.getIIntentReceiver();30. 31. 32. 33. .34. 35. staticfinalclassReceiverDispatcher36. 37. finalstaticclassInnerReceiverextendsIIntentReceiver.Stub38. finalWeakReferencemDispatcher;39. .40. 41. InnerReceiver(LoadedApk.ReceiverDispatcherrd,booleanstrong)42. mDispatcher=newWeakReference(rd);43. .44. 45. 46. .47. 48. 49. .50. 51. finalIIntentReceiver.StubmIIntentReceiver;52. finalHandlermActivityThread;53. 54. .55. 56. ReceiverDispatcher(BroadcastReceiverreceiver,Contextcontext,57. HandleractivityThread,Instrumentationinstrumentation,58. booleanregistered)59. .60. 61. mIIntentReceiver=newInnerReceiver(this,!registered);62. mActivityThread=activityThread;63. 64. .65. 66. 67. .68. 69. IIntentReceivergetIIntentReceiver()70. returnmIIntentReceiver;71. 72. 73. 74. 75. .76. 77. 在LoadedApk.getReceiverDispatcher函数中,首先看一下参数r是不是已经有相应的ReceiverDispatcher存在了,如果有,就直接返回了,否则就新建一个ReceiverDispatcher,并且以r为Key值保在一个HashMap中,而这个HashMap以Context,这里即为MainActivity为Key值保存在LoadedApk的成员变量mReceivers中,这样,只要给定一个Activity和BroadcastReceiver,就可以查看LoadedApk里面是否已经存在相应的广播接收发布器ReceiverDispatcher了。 在新建广播接收发布器ReceiverDispatcher时,会在构造函数里面创建一个InnerReceiver实例,这是一个Binder对象,实现了IIntentReceiver接口,可以通过ReceiverDispatcher.getIIntentReceiver函数来获得,获得后就会把它传给ActivityManagerService,以便接收广播。在ReceiverDispatcher类的构造函数中,还会把传进来的Handle类型的参数activityThread保存下来,以便后面在分发广播的时候使用。 现在,再回到ContextImpl.registerReceiverInternal函数,在获得了IIntentReceiver类型的Binder对象后,就开始要把它注册到ActivityManagerService中去了。 Step 5. ActivityManagerProxy.registerReceiver 这个函数实现在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:view plain1. classActivityManagerProxyimplementsIActivityManager2. 3. .4. 5. publicIntentregisterReceiver(IApplicationThreadcaller,6. IIntentReceiverreceiver,7. IntentFilterfilter,Stringperm)throwsRemoteException8. 9. Parceldata=Parcel.obtain();10. Parcelreply=Parcel.obtain();11. data.writeInterfaceToken(IActivityManager.descriptor);12. data.writeStrongBinder(caller!=null?caller.asBinder():null);13. data.writeStrongBinder(receiver!=null?receiver.asBinder():null);14. filter.writeToParcel(data,0);15. data.writeString(perm);16. mRemote.transact(REGISTER_RECEIVER_TRANSACTION,data,reply,0);17. reply.readException();18. Intentintent=null;19. inthaveIntent=reply.readInt();20. if(haveIntent!=0)21. intent=Intent.CREATOR.createFromParcel(reply);22. 23. reply.recycle();24. data.recycle();25. returnintent;26. 27. 28. .29. 30. 这个函数通过Binder驱动程序就进入到ActivityManagerService中的registerReceiver函数中去了。 Step 6. ActivityManagerService.registerReceiver 这个函数实现在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:view plain1. publicfinalclassActivityManagerServiceextendsActivityManagerNative2. implementsWatchdog.Monitor,BatteryStatsImpl.BatteryCallback3. .4. 5. publicIntentregisterReceiver(IApplicationThreadcaller,6. IIntentReceiverreceiver,IntentFilterfilter,Stringpermission)7. synchronized(this)8. ProcessRecordcallerApp=null;9. if(caller!=null)10. callerApp=getRecordForAppLocked(caller);11. if(callerApp=null)12. .13. 14. 15. 16. ListallSticky=null;17. 18. /Lookforanymatchingstickybroadcasts.19. Iteratoractions=filter.actionsIterator();20. if(actions!=null)21. while(actions.hasNext()22. Stringaction=(String)actions.next();23. allSticky=getStickiesLocked(action,filter,allSticky);24. 25. else26. .27. 28. 29. /Thefirststickyinthelistisreturneddirectlybackto30. /theclient.31. Intentsticky=allSticky!=null?(Intent)allSticky.get(0):null;32. 33. .34. 35. if(receiver=null)36. returnsticky;37. 38. 39. ReceiverListrl40. =(ReceiverList)mRegisteredReceivers.get(receiver.asBinder();41. if(rl=null)42. rl=newReceiverList(this,callerApp,43. Binder.getCallingPid(),44. Binder.getCallingUid(),receiver);45. 46. if(rl.app!=null)47. rl.app.receivers.add(rl);48. else49. .50. 51. mRegisteredReceivers.put(receiver.asBinder(),rl);52. 53. 54. BroadcastFilterbf=newBroadcastFilter(filter,rl,permission);55. rl.add(bf);56. .57. mReceiverResolver.addFilter(bf);58. 59. /Enqueuebroadcastsforallexistingstickiesthatmatch60. /thisfilter.61. if(allSticky!=null)62. .63. 64. 65. returnsticky;66. 67. 68. 69. .70. 71. 函数首先是获得调用registerReceiver函数的应用程序进程记录块:view plain1. ProcessRecordcallerApp=null;2. if(caller!=null)3. callerApp=getRecordForAppLocked(caller);4. if(callerApp=null)5. .6. 7. 这里得到的便是上一篇文章Android系统中的广播(Broadcast)机制简要介绍和学习计划里面介绍的应用程序Broadcast的进程记录块了,MainActivity就是在里面启动起来的。 view plain1. ListallSticky=null;2. 3. /Lookforanymatchingstickybroadcasts.4. Iteratoractions=filter.actionsIterator();5. if(actions!=null)6. while(actions.hasNext()7. Stringaction=(String)actions.next();8. allSticky=getStickiesLocked(action,filter,allSticky);9. 10. else11. .12. 13. 14. /Thefirststickyinthelistisreturneddirectlybackto15. /theclient.16. Intentsticky=allSticky!=null?(Intent)allSticky.get(0):null; 这里传进来的filter只有一个action,就是前面描述的CounterService.BROADCAST_COUNTER_ACTION了,这里先通过getStickiesLocked函数查找一下有没有对应的sticky intent列表存在。什么是Sticky Intent呢?我们在最后一次调用sendStickyBroadcast函数来发送某个Action类型的广播时,系统会把代表这个广播的Intent保存下来,这样,后来调用registerReceiver来注册相同Action类型的广播接收器,就会得到这个最后发出的广播。这就是为什么叫做Sticky Intent了,这个最后发出的广播虽然被处理完了,但是仍然被粘住在ActivityManagerService中,以便下一个注册相应Action类型的广播接收

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论