`
苗振忠
  • 浏览: 51725 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

EventBus---EventBus源码解析 带你深入理解EventBus

 
阅读更多

转载自:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:【张鸿洋的博客】

上一篇带大家初步了解了EventBus的使用方式,详见:Android EventBus实战 没听过你就out了,本篇博客将解析EventBus的源码,相信能够让大家深入理解该框架的实现,也能解决很多在使用中的疑问:为什么可以这么做?为什么这么做不好呢?

1、概述

一般使用EventBus的组件类,类似下面这种方式:

  1. publicclassSampleComponentextendsFragment
  2. {
  3. @Override
  4. publicvoidonCreate(BundlesavedInstanceState)
  5. {
  6. super.onCreate(savedInstanceState);
  7. EventBus.getDefault().register(this);
  8. }
  9. publicvoidonEventMainThread(param)
  10. {
  11. }
  12. publicvoidonEventPostThread(param)
  13. {
  14. }
  15. publicvoidonEventBackgroundThread(param)
  16. {
  17. }
  18. publicvoidonEventAsync(param)
  19. {
  20. }
  21. @Override
  22. publicvoidonDestroy()
  23. {
  24. super.onDestroy();
  25. EventBus.getDefault().unregister(this);
  26. }
  27. }
  1. <spanstyle="font-size:14px;">publicclassSampleComponentextendsFragment
  2. {
  3. @Override
  4. publicvoidonCreate(BundlesavedInstanceState)
  5. {
  6. super.onCreate(savedInstanceState);
  7. EventBus.getDefault().register(this);
  8. }
  9. publicvoidonEventMainThread(param)
  10. {
  11. }
  12. publicvoidonEventPostThread(param)
  13. {
  14. }
  15. publicvoidonEventBackgroundThread(param)
  16. {
  17. }
  18. publicvoidonEventAsync(param)
  19. {
  20. }
  21. @Override
  22. publicvoidonDestroy()
  23. {
  24. super.onDestroy();
  25. EventBus.getDefault().unregister(this);
  26. }
  27. }</span>


大多情况下,都会在onCreate中进行register,在onDestory中进行unregister ;

看完代码大家或许会有一些疑问:

1、代码中还有一些以onEvent开头的方法,这些方法是干嘛的呢?

在回答这个问题之前,我有一个问题,你咋不问register(this)是干嘛的呢?其实register(this)就是去当前类,遍历所有的方法,找到onEvent开头的然后进行存储。现在知道onEvent开头的方法是干嘛的了吧。

2、那onEvent后面的那些MainThread应该是什么标志吧?

嗯,是的,onEvent后面可以写四种,也就是上面出现的四个方法,决定了当前的方法最终在什么线程运行,怎么运行,可以参考上一篇博客或者细细往下看。


既然register了,那么肯定得说怎么调用是吧。

  1. EventBus.getDefault().post(param);
  1. <spanstyle="font-size:14px;">EventBus.getDefault().post(param);</span>


调用很简单,一句话,你也可以叫发布,只要把这个param发布出去,EventBus会在它内部存储的方法中,进行扫描,找到参数匹配的,就使用反射进行调用。

现在有没有觉得,撇开专业术语:其实EventBus就是在内部存储了一堆onEvent开头的方法,然后post的时候,根据post传入的参数,去找到匹配的方法,反射调用之。

那么,我告诉你,它内部使用了Map进行存储,键就是参数的Class类型。知道是这个类型,那么你觉得根据post传入的参数进行查找还是个事么?


下面我们就去看看EventBus的register和post真面目。

2、register

EventBus.getDefault().register(this);

首先:

EventBus.getDefault()其实就是个单例,和我们传统的getInstance一个意思:

  1. /**Conveniencesingletonforappsusingaprocess-wideEventBusinstance.*/
  2. publicstaticEventBusgetDefault(){
  3. if(defaultInstance==null){
  4. synchronized(EventBus.class){
  5. if(defaultInstance==null){
  6. defaultInstance=newEventBus();
  7. }
  8. }
  9. }
  10. returndefaultInstance;
  11. }
  1. <spanstyle="font-size:14px;">/**Conveniencesingletonforappsusingaprocess-wideEventBusinstance.*/
  2. publicstaticEventBusgetDefault(){
  3. if(defaultInstance==null){
  4. synchronized(EventBus.class){
  5. if(defaultInstance==null){
  6. defaultInstance=newEventBus();
  7. }
  8. }
  9. }
  10. returndefaultInstance;
  11. }</span>


使用了双重判断的方式,防止并发的问题,还能极大的提高效率。

然后register应该是一个普通的方法,我们去看看:

register公布给我们使用的有4个:

  1. publicvoidregister(Objectsubscriber){
  2. register(subscriber,DEFAULT_METHOD_NAME,false,0);
  3. }
  4. publicvoidregister(Objectsubscriber,intpriority){
  5. register(subscriber,DEFAULT_METHOD_NAME,false,priority);
  6. }
  7. publicvoidregisterSticky(Objectsubscriber){
  8. register(subscriber,DEFAULT_METHOD_NAME,true,0);
  9. }
  10. publicvoidregisterSticky(Objectsubscriber,intpriority){
  11. register(subscriber,DEFAULT_METHOD_NAME,true,priority);
  12. }
  1. <spanstyle="font-size:14px;">publicvoidregister(Objectsubscriber){
  2. register(subscriber,DEFAULT_METHOD_NAME,false,0);
  3. }
  4. publicvoidregister(Objectsubscriber,intpriority){
  5. register(subscriber,DEFAULT_METHOD_NAME,false,priority);
  6. }
  7. publicvoidregisterSticky(Objectsubscriber){
  8. register(subscriber,DEFAULT_METHOD_NAME,true,0);
  9. }
  10. publicvoidregisterSticky(Objectsubscriber,intpriority){
  11. register(subscriber,DEFAULT_METHOD_NAME,true,priority);
  12. }</span>


本质上就调用了同一个:

  1. privatesynchronizedvoidregister(Objectsubscriber,StringmethodName,booleansticky,intpriority){
  2. List<SubscriberMethod>subscriberMethods=subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(),
  3. methodName);
  4. for(SubscriberMethodsubscriberMethod:subscriberMethods){
  5. subscribe(subscriber,subscriberMethod,sticky,priority);
  6. }
  7. }
  1. <spanstyle="font-size:14px;">privatesynchronizedvoidregister(Objectsubscriber,StringmethodName,booleansticky,intpriority){
  2. List<SubscriberMethod>subscriberMethods=subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(),
  3. methodName);
  4. for(SubscriberMethodsubscriberMethod:subscriberMethods){
  5. subscribe(subscriber,subscriberMethod,sticky,priority);
  6. }
  7. }</span>


四个参数

subscriber是我们扫描类的对象,也就是我们代码中常见的this;

methodName 这个是写死的:“onEvent”,用于确定扫描什么开头的方法,可见我们的类中都是以这个开头。

sticky 这个参数,解释源码的时候解释,暂时不用管

priority 优先级,优先级越高,在调用的时候会越先调用。

下面开始看代码:

  1. List<SubscriberMethod>subscriberMethods=subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(),
  2. methodName);
  1. <spanstyle="font-size:14px;">List<SubscriberMethod>subscriberMethods=subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(),
  2. methodName);</span>


调用内部类SubscriberMethodFinder的findSubscriberMethods方法,传入了subscriber 的class,以及methodName,返回一个List<SubscriberMethod>。

那么不用说,肯定是去遍历该类内部所有方法,然后根据methodName去匹配,匹配成功的封装成SubscriberMethod,最后返回一个List。下面看代码:

  1. List<SubscriberMethod>findSubscriberMethods(Class<?>subscriberClass,StringeventMethodName){
  2. Stringkey=subscriberClass.getName()+'.'+eventMethodName;
  3. List<SubscriberMethod>subscriberMethods;
  4. synchronized(methodCache){
  5. subscriberMethods=methodCache.get(key);
  6. }
  7. if(subscriberMethods!=null){
  8. returnsubscriberMethods;
  9. }
  10. subscriberMethods=newArrayList<SubscriberMethod>();
  11. Class<?>clazz=subscriberClass;
  12. HashSet<String>eventTypesFound=newHashSet<String>();
  13. StringBuildermethodKeyBuilder=newStringBuilder();
  14. while(clazz!=null){
  15. Stringname=clazz.getName();
  16. if(name.startsWith("java.")||name.startsWith("javax.")||name.startsWith("android.")){
  17. //Skipsystemclasses,thisjustdegradesperformance
  18. break;
  19. }
  20. //StartingwithEventBus2.2weenforcedmethodstobepublic(mightchangewithannotationsagain)
  21. Method[]methods=clazz.getMethods();
  22. for(Methodmethod:methods){
  23. StringmethodName=method.getName();
  24. if(methodName.startsWith(eventMethodName)){
  25. intmodifiers=method.getModifiers();
  26. if((modifiers&Modifier.PUBLIC)!=0&&(modifiers&MODIFIERS_IGNORE)==0){
  27. Class<?>[]parameterTypes=method.getParameterTypes();
  28. if(parameterTypes.length==1){
  29. StringmodifierString=methodName.substring(eventMethodName.length());
  30. ThreadModethreadMode;
  31. if(modifierString.length()==0){
  32. threadMode=ThreadMode.PostThread;
  33. }elseif(modifierString.equals("MainThread")){
  34. threadMode=ThreadMode.MainThread;
  35. }elseif(modifierString.equals("BackgroundThread")){
  36. threadMode=ThreadMode.BackgroundThread;
  37. }elseif(modifierString.equals("Async")){
  38. threadMode=ThreadMode.Async;
  39. }else{
  40. if(skipMethodVerificationForClasses.containsKey(clazz)){
  41. continue;
  42. }else{
  43. thrownewEventBusException("IllegalonEventmethod,checkfortypos:"+method);
  44. }
  45. }
  46. Class<?>eventType=parameterTypes[0];
  47. methodKeyBuilder.setLength(0);
  48. methodKeyBuilder.append(methodName);
  49. methodKeyBuilder.append('>').append(eventType.getName());
  50. StringmethodKey=methodKeyBuilder.toString();
  51. if(eventTypesFound.add(methodKey)){
  52. //Onlyaddifnotalreadyfoundinasubclass
  53. subscriberMethods.add(newSubscriberMethod(method,threadMode,eventType));
  54. }
  55. }
  56. }elseif(!skipMethodVerificationForClasses.containsKey(clazz)){
  57. Log.d(EventBus.TAG,"Skippingmethod(notpublic,staticorabstract):"+clazz+"."
  58. +methodName);
  59. }
  60. }
  61. }
  62. clazz=clazz.getSuperclass();
  63. }
  64. if(subscriberMethods.isEmpty()){
  65. thrownewEventBusException("Subscriber"+subscriberClass+"hasnopublicmethodscalled"
  66. +eventMethodName);
  67. }else{
  68. synchronized(methodCache){
  69. methodCache.put(key,subscriberMethods);
  70. }
  71. returnsubscriberMethods;
  72. }
  73. }
  1. <spanstyle="font-size:14px;">List<SubscriberMethod>findSubscriberMethods(Class<?>subscriberClass,StringeventMethodName){
  2. Stringkey=subscriberClass.getName()+'.'+eventMethodName;
  3. List<SubscriberMethod>subscriberMethods;
  4. synchronized(methodCache){
  5. subscriberMethods=methodCache.get(key);
  6. }
  7. if(subscriberMethods!=null){
  8. returnsubscriberMethods;
  9. }
  10. subscriberMethods=newArrayList<SubscriberMethod>();
  11. Class<?>clazz=subscriberClass;
  12. HashSet<String>eventTypesFound=newHashSet<String>();
  13. StringBuildermethodKeyBuilder=newStringBuilder();
  14. while(clazz!=null){
  15. Stringname=clazz.getName();
  16. if(name.startsWith("java.")||name.startsWith("javax.")||name.startsWith("android.")){
  17. //Skipsystemclasses,thisjustdegradesperformance
  18. break;
  19. }
  20. //StartingwithEventBus2.2weenforcedmethodstobepublic(mightchangewithannotationsagain)
  21. Method[]methods=clazz.getMethods();
  22. for(Methodmethod:methods){
  23. StringmethodName=method.getName();
  24. if(methodName.startsWith(eventMethodName)){
  25. intmodifiers=method.getModifiers();
  26. if((modifiers&Modifier.PUBLIC)!=0&&(modifiers&MODIFIERS_IGNORE)==0){
  27. Class<?>[]parameterTypes=method.getParameterTypes();
  28. if(parameterTypes.length==1){
  29. StringmodifierString=methodName.substring(eventMethodName.length());
  30. ThreadModethreadMode;
  31. if(modifierString.length()==0){
  32. threadMode=ThreadMode.PostThread;
  33. }elseif(modifierString.equals("MainThread")){
  34. threadMode=ThreadMode.MainThread;
  35. }elseif(modifierString.equals("BackgroundThread")){
  36. threadMode=ThreadMode.BackgroundThread;
  37. }elseif(modifierString.equals("Async")){
  38. threadMode=ThreadMode.Async;
  39. }else{
  40. if(skipMethodVerificationForClasses.containsKey(clazz)){
  41. continue;
  42. }else{
  43. thrownewEventBusException("IllegalonEventmethod,checkfortypos:"+method);
  44. }
  45. }
  46. Class<?>eventType=parameterTypes[0];
  47. methodKeyBuilder.setLength(0);
  48. methodKeyBuilder.append(methodName);
  49. methodKeyBuilder.append('>').append(eventType.getName());
  50. StringmethodKey=methodKeyBuilder.toString();
  51. if(eventTypesFound.add(methodKey)){
  52. //Onlyaddifnotalreadyfoundinasubclass
  53. subscriberMethods.add(newSubscriberMethod(method,threadMode,eventType));
  54. }
  55. }
  56. }elseif(!skipMethodVerificationForClasses.containsKey(clazz)){
  57. Log.d(EventBus.TAG,"Skippingmethod(notpublic,staticorabstract):"+clazz+"."
  58. +methodName);
  59. }
  60. }
  61. }
  62. clazz=clazz.getSuperclass();
  63. }
  64. if(subscriberMethods.isEmpty()){
  65. thrownewEventBusException("Subscriber"+subscriberClass+"hasnopublicmethodscalled"
  66. +eventMethodName);
  67. }else{
  68. synchronized(methodCache){
  69. methodCache.put(key,subscriberMethods);
  70. }
  71. returnsubscriberMethods;
  72. }
  73. }</span>

呵,代码还真长;不过我们直接看核心部分:

22行:看到没,clazz.getMethods();去得到所有的方法:

23-62行:就开始遍历每一个方法了,去匹配封装了。

25-29行:分别判断了是否以onEvent开头,是否是public且非static和abstract方法,是否是一个参数。如果都复合,才进入封装的部分。

32-45行:也比较简单,根据方法的后缀,来确定threadMode,threadMode是个枚举类型:就四种情况。

最后在54行:将method, threadMode, eventType传入构造了:new SubscriberMethod(method, threadMode, eventType)。添加到List,最终放回。

注意下63行:clazz = clazz.getSuperclass();可以看到,会扫描所有的父类,不仅仅是当前类。

继续回到register:

  1. for(SubscriberMethodsubscriberMethod:subscriberMethods){
  2. subscribe(subscriber,subscriberMethod,sticky,priority);
  3. }
  1. <spanstyle="font-size:14px;">for(SubscriberMethodsubscriberMethod:subscriberMethods){
  2. subscribe(subscriber,subscriberMethod,sticky,priority);
  3. }</span>


for循环扫描到的方法,然后去调用suscribe方法。

  1. //Mustbecalledinsynchronizedblock
  2. privatevoidsubscribe(Objectsubscriber,SubscriberMethodsubscriberMethod,booleansticky,intpriority){
  3. subscribed=true;
  4. Class<?>eventType=subscriberMethod.eventType;
  5. CopyOnWriteArrayList<Subscription>subscriptions=subscriptionsByEventType.get(eventType);
  6. SubscriptionnewSubscription=newSubscription(subscriber,subscriberMethod,priority);
  7. if(subscriptions==null){
  8. subscriptions=newCopyOnWriteArrayList<Subscription>();
  9. subscriptionsByEventType.put(eventType,subscriptions);
  10. }else{
  11. for(Subscriptionsubscription:subscriptions){
  12. if(subscription.equals(newSubscription)){
  13. thrownewEventBusException("Subscriber"+subscriber.getClass()+"alreadyregisteredtoevent"
  14. +eventType);
  15. }
  16. }
  17. }
  18. //StartingwithEventBus2.2weenforcedmethodstobepublic(mightchangewithannotationsagain)
  19. //subscriberMethod.method.setAccessible(true);
  20. intsize=subscriptions.size();
  21. for(inti=0;i<=size;i++){
  22. if(i==size||newSubscription.priority>subscriptions.get(i).priority){
  23. subscriptions.add(i,newSubscription);
  24. break;
  25. }
  26. }
  27. List<Class<?>>subscribedEvents=typesBySubscriber.get(subscriber);
  28. if(subscribedEvents==null){
  29. subscribedEvents=newArrayList<Class<?>>();
  30. typesBySubscriber.put(subscriber,subscribedEvents);
  31. }
  32. subscribedEvents.add(eventType);
  33. if(sticky){
  34. ObjectstickyEvent;
  35. synchronized(stickyEvents){
  36. stickyEvent=stickyEvents.get(eventType);
  37. }
  38. if(stickyEvent!=null){
  39. //Ifthesubscriberistryingtoaborttheevent,itwillfail(eventisnottrackedinpostingstate)
  40. //-->Strangecornercase,whichwedon'ttakecareofhere.
  41. postToSubscription(newSubscription,stickyEvent,Looper.getMainLooper()==Looper.myLooper());
  42. }
  43. }
  44. }
  1. <spanstyle="font-size:14px;">//Mustbecalledinsynchronizedblock
  2. privatevoidsubscribe(Objectsubscriber,SubscriberMethodsubscriberMethod,booleansticky,intpriority){
  3. subscribed=true;
  4. Class<?>eventType=subscriberMethod.eventType;
  5. CopyOnWriteArrayList<Subscription>subscriptions=subscriptionsByEventType.get(eventType);
  6. SubscriptionnewSubscription=newSubscription(subscriber,subscriberMethod,priority);
  7. if(subscriptions==null){
  8. subscriptions=newCopyOnWriteArrayList<Subscription>();
  9. subscriptionsByEventType.put(eventType,subscriptions);
  10. }else{
  11. for(Subscriptionsubscription:subscriptions){
  12. if(subscription.equals(newSubscription)){
  13. thrownewEventBusException("Subscriber"+subscriber.getClass()+"alreadyregisteredtoevent"
  14. +eventType);
  15. }
  16. }
  17. }
  18. //StartingwithEventBus2.2weenforcedmethodstobepublic(mightchangewithannotationsagain)
  19. //subscriberMethod.method.setAccessible(true);
  20. intsize=subscriptions.size();
  21. for(inti=0;i<=size;i++){
  22. if(i==size||newSubscription.priority>subscriptions.get(i).priority){
  23. subscriptions.add(i,newSubscription);
  24. break;
  25. }
  26. }
  27. List<Class<?>>subscribedEvents=typesBySubscriber.get(subscriber);
  28. if(subscribedEvents==null){
  29. subscribedEvents=newArrayList<Class<?>>();
  30. typesBySubscriber.put(subscriber,subscribedEvents);
  31. }
  32. subscribedEvents.add(eventType);
  33. if(sticky){
  34. ObjectstickyEvent;
  35. synchronized(stickyEvents){
  36. stickyEvent=stickyEvents.get(eventType);
  37. }
  38. if(stickyEvent!=null){
  39. //Ifthesubscriberistryingtoaborttheevent,itwillfail(eventisnottrackedinpostingstate)
  40. //-->Strangecornercase,whichwedon'ttakecareofhere.
  41. postToSubscription(newSubscription,stickyEvent,Looper.getMainLooper()==Looper.myLooper());
  42. }
  43. }
  44. }</span>

我们的subscriberMethod中保存了method, threadMode, eventType,上面已经说了;

4-17行:根据subscriberMethod.eventType,去subscriptionsByEventType去查找一个CopyOnWriteArrayList<Subscription> ,如果没有则创建。

顺便把我们的传入的参数封装成了一个:Subscription(subscriber, subscriberMethod, priority);

这里的subscriptionsByEventType是个Map,key:eventType ; value:CopyOnWriteArrayList<Subscription> ;这个Map其实就是EventBus存储方法的地方,一定要记住!

22-28行:实际上,就是添加newSubscription;并且是按照优先级添加的。可以看到,优先级越高,会插到在当前List的前面。

30-35行:根据subscriber存储它所有的eventType ; 依然是map;key:subscriber ,value:List<eventType> ;知道就行,非核心代码,主要用于isRegister的判断。

37-47行:判断sticky;如果为true,从stickyEvents中根据eventType去查找有没有stickyEvent,如果有则立即发布去执行。stickyEvent其实就是我们post时的参数。

postToSubscription这个方法,我们在post的时候会介绍。


到此,我们register就介绍完了。

你只要记得一件事:扫描了所有的方法,把匹配的方法最终保存在subscriptionsByEventType(Map,key:eventType ; value:CopyOnWriteArrayList<Subscription>)中;

eventType是我们方法参数的Class,Subscription中则保存着subscriber, subscriberMethod(method, threadMode, eventType), priority;包含了执行改方法所需的一切。


3、post

register完毕,知道了EventBus如何存储我们的方法了,下面看看post它又是如何调用我们的方法的。

再看源码之前,我们猜测下:register时,把方法存在subscriptionsByEventType;那么post肯定会去subscriptionsByEventType去取方法,然后调用。

下面看源码:

  1. /**Poststhegiveneventtotheeventbus.*/
  2. publicvoidpost(Objectevent){
  3. PostingThreadStatepostingState=currentPostingThreadState.get();
  4. List<Object>eventQueue=postingState.eventQueue;
  5. eventQueue.add(event);
  6. if(postingState.isPosting){
  7. return;
  8. }else{
  9. postingState.isMainThread=Looper.getMainLooper()==Looper.myLooper();
  10. postingState.isPosting=true;
  11. if(postingState.canceled){
  12. thrownewEventBusException("Internalerror.Abortstatewasnotreset");
  13. }
  14. try{
  15. while(!eventQueue.isEmpty()){
  16. postSingleEvent(eventQueue.remove(0),postingState);
  17. }
  18. }finally{
  19. postingState.isPosting=false;
  20. postingState.isMainThread=false;
  21. }
  22. }
  23. }
  1. <spanstyle="font-size:14px;">/**Poststhegiveneventtotheeventbus.*/
  2. publicvoidpost(Objectevent){
  3. PostingThreadStatepostingState=currentPostingThreadState.get();
  4. List<Object>eventQueue=postingState.eventQueue;
  5. eventQueue.add(event);
  6. if(postingState.isPosting){
  7. return;
  8. }else{
  9. postingState.isMainThread=Looper.getMainLooper()==Looper.myLooper();
  10. postingState.isPosting=true;
  11. if(postingState.canceled){
  12. thrownewEventBusException("Internalerror.Abortstatewasnotreset");
  13. }
  14. try{
  15. while(!eventQueue.isEmpty()){
  16. postSingleEvent(eventQueue.remove(0),postingState);
  17. }
  18. }finally{
  19. postingState.isPosting=false;
  20. postingState.isMainThread=false;
  21. }
  22. }
  23. }</span>

currentPostingThreadState是一个ThreadLocal类型的,里面存储了PostingThreadState;PostingThreadState包含了一个eventQueue和一些标志位。

  1. privatefinalThreadLocal<PostingThreadState>currentPostingThreadState=newThreadLocal<PostingThreadState>(){
  2. @Override
  3. protectedPostingThreadStateinitialValue(){
  4. returnnewPostingThreadState();
  5. }
  6. }
  1. <spanstyle="font-size:14px;">privatefinalThreadLocal<PostingThreadState>currentPostingThreadState=newThreadLocal<PostingThreadState>(){
  2. @Override
  3. protectedPostingThreadStateinitialValue(){
  4. returnnewPostingThreadState();
  5. }
  6. }</span>


把我们传入的event,保存到了当前线程中的一个变量PostingThreadState的eventQueue中。

10行:判断当前是否是UI线程。

16-18行:遍历队列中的所有的event,调用postSingleEvent(eventQueue.remove(0), postingState)方法。

这里大家会不会有疑问,每次post都会去调用整个队列么,那么不会造成方法多次调用么?

可以看到第7-8行,有个判断,就是防止该问题的,isPosting=true了,就不会往下走了。


下面看postSingleEvent

  1. privatevoidpostSingleEvent(Objectevent,PostingThreadStatepostingState)throwsError{
  2. Class<?extendsObject>eventClass=event.getClass();
  3. List<Class<?>>eventTypes=findEventTypes(eventClass);
  4. booleansubscriptionFound=false;
  5. intcountTypes=eventTypes.size();
  6. for(inth=0;h<countTypes;h++){
  7. Class<?>clazz=eventTypes.get(h);
  8. CopyOnWriteArrayList<Subscription>subscriptions;
  9. synchronized(this){
  10. subscriptions=subscriptionsByEventType.get(clazz);
  11. }
  12. if(subscriptions!=null&&!subscriptions.isEmpty()){
  13. for(Subscriptionsubscription:subscriptions){
  14. postingState.event=event;
  15. postingState.subscription=subscription;
  16. booleanaborted=false;
  17. try{
  18. postToSubscription(subscription,event,postingState.isMainThread);
  19. aborted=postingState.canceled;
  20. }finally{
  21. postingState.event=null;
  22. postingState.subscription=null;
  23. postingState.canceled=false;
  24. }
  25. if(aborted){
  26. break;
  27. }
  28. }
  29. subscriptionFound=true;
  30. }
  31. }
  32. if(!subscriptionFound){
  33. Log.d(TAG,"Nosubscribersregisteredforevent"+eventClass);
  34. if(eventClass!=NoSubscriberEvent.class&&eventClass!=SubscriberExceptionEvent.class){
  35. post(newNoSubscriberEvent(this,event));
  36. }
  37. }
  38. }
  1. <spanstyle="font-size:14px;">privatevoidpostSingleEvent(Objectevent,PostingThreadStatepostingState)throwsError{
  2. Class<?extendsObject>eventClass=event.getClass();
  3. List<Class<?>>eventTypes=findEventTypes(eventClass);
  4. booleansubscriptionFound=false;
  5. intcountTypes=eventTypes.size();
  6. for(inth=0;h<countTypes;h++){
  7. Class<?>clazz=eventTypes.get(h);
  8. CopyOnWriteArrayList<Subscription>subscriptions;
  9. synchronized(this){
  10. subscriptions=subscriptionsByEventType.get(clazz);
  11. }
  12. if(subscriptions!=null&&!subscriptions.isEmpty()){
  13. for(Subscriptionsubscription:subscriptions){
  14. postingState.event=event;
  15. postingState.subscription=subscription;
  16. booleanaborted=false;
  17. try{
  18. postToSubscription(subscription,event,postingState.isMainThread);
  19. aborted=postingState.canceled;
  20. }finally{
  21. postingState.event=null;
  22. postingState.subscription=null;
  23. postingState.canceled=false;
  24. }
  25. if(aborted){
  26. break;
  27. }
  28. }
  29. subscriptionFound=true;
  30. }
  31. }
  32. if(!subscriptionFound){
  33. Log.d(TAG,"Nosubscribersregisteredforevent"+eventClass);
  34. if(eventClass!=NoSubscriberEvent.class&&eventClass!=SubscriberExceptionEvent.class){
  35. post(newNoSubscriberEvent(this,event));
  36. }
  37. }
  38. }</span>


将我们的event,即post传入的实参;以及postingState传入到postSingleEvent中。

2-3行:根据event的Class,去得到一个List<Class<?>>;其实就是得到event当前对象的Class,以及父类和接口的Class类型;主要用于匹配,比如你传入Dog extends Dog,他会把Animal也装到该List中。

6-31行:遍历所有的Class,到subscriptionsByEventType去查找subscriptions;哈哈,熟不熟悉,还记得我们register里面把方法存哪了不?

是不是就是这个Map;

12-30行:遍历每个subscription,依次去调用postToSubscription(subscription, event, postingState.isMainThread);
这个方法就是去反射执行方法了,大家还记得在register,if(sticky)时,也会去执行这个方法。

下面看它如何反射执行:

  1. privatevoidpostToSubscription(Subscriptionsubscription,Objectevent,booleanisMainThread){
  2. switch(subscription.subscriberMethod.threadMode){
  3. casePostThread:
  4. invokeSubscriber(subscription,event);
  5. break;
  6. caseMainThread:
  7. if(isMainThread){
  8. invokeSubscriber(subscription,event);
  9. }else{
  10. mainThreadPoster.enqueue(subscription,event);
  11. }
  12. break;
  13. caseBackgroundThread:
  14. if(isMainThread){
  15. backgroundPoster.enqueue(subscription,event);
  16. }else{
  17. invokeSubscriber(subscription,event);
  18. }
  19. break;
  20. caseAsync:
  21. asyncPoster.enqueue(subscription,event);
  22. break;
  23. default:
  24. thrownewIllegalStateException("Unknownthreadmode:"+subscription.subscriberMethod.threadMode);
  25. }
  26. }
  1. <spanstyle="font-size:14px;">privatevoidpostToSubscription(Subscriptionsubscription,Objectevent,booleanisMainThread){
  2. switch(subscription.subscriberMethod.threadMode){
  3. casePostThread:
  4. invokeSubscriber(subscription,event);
  5. break;
  6. caseMainThread:
  7. if(isMainThread){
  8. invokeSubscriber(subscription,event);
  9. }else{
  10. mainThreadPoster.enqueue(subscription,event);
  11. }
  12. break;
  13. caseBackgroundThread:
  14. if(isMainThread){
  15. backgroundPoster.enqueue(subscription,event);
  16. }else{
  17. invokeSubscriber(subscription,event);
  18. }
  19. break;
  20. caseAsync:
  21. asyncPoster.enqueue(subscription,event);
  22. break;
  23. default:
  24. thrownewIllegalStateException("Unknownthreadmode:"+subscription.subscriberMethod.threadMode);
  25. }
  26. }
  27. </span>

前面已经说过subscription包含了所有执行需要的东西,大致有:subscriber, subscriberMethod(method, threadMode, eventType), priority;

那么这个方法:第一步根据threadMode去判断应该在哪个线程去执行该方法;
case PostThread:

  1. voidinvokeSubscriber(Subscriptionsubscription,Objectevent)throwsError{
  2. subscription.subscriberMethod.method.invoke(subscription.subscriber,event);
  1. <spanstyle="font-size:14px;">voidinvokeSubscriber(Subscriptionsubscription,Objectevent)throwsError{
  2. subscription.subscriberMethod.method.invoke(subscription.subscriber,event);
  3. </span>


直接反射调用;也就是说在当前的线程直接调用该方法;

case MainThread:

首先去判断当前如果是UI线程,则直接调用;否则:mainThreadPoster.enqueue(subscription, event);把当前的方法加入到队列,然后直接通过handler去发送一个消息,在handler的handleMessage中,去执行我们的方法。说白了就是通过Handler去发送消息,然后执行的。

case BackgroundThread:

如果当前非UI线程,则直接调用;如果是UI线程,则将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用

executorService = Executors.newCachedThreadPool();。

case Async:将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用;线程池与BackgroundThread用的是同一个。

这么说BackgroundThread和Async有什么区别呢?

BackgroundThread中的任务,一个接着一个去调用,中间使用了一个布尔型变量handlerActive进行的控制。

Async则会动态控制并发。


到此,我们完整的源码分析就结束了,总结一下:register会把当前类中匹配的方法,存入一个map,而post会根据实参去map查找进行反射调用。分析这么久,一句话就说完了~~

其实不用发布者,订阅者,事件,总线这几个词或许更好理解,以后大家问了EventBus,可以说,就是在一个单例内部维持着一个map对象存储了一堆的方法;post无非就是根据参数去查找方法,进行反射调用。


4、其余方法

介绍了register和post;大家获取还能想到一个词sticky,在register中,如何sticky为true,会去stickyEvents去查找事件,然后立即去post;

那么这个stickyEvents何时进行保存事件呢?

其实evevntbus中,除了post发布事件,还有一个方法也可以:

  1. publicvoidpostSticky(Objectevent){
  2. synchronized(stickyEvents){
  3. stickyEvents.put(event.getClass(),event);
  4. }
  5. //Shouldbepostedafteritisputted,incasethesubscriberwantstoremoveimmediately
  6. post(event);
  7. }
  1. <spanstyle="font-size:14px;">publicvoidpostSticky(Objectevent){
  2. synchronized(stickyEvents){
  3. stickyEvents.put(event.getClass(),event);
  4. }
  5. //Shouldbepostedafteritisputted,incasethesubscriberwantstoremoveimmediately
  6. post(event);
  7. }</span>


和post功能类似,但是会把方法存储到stickyEvents中去;

大家再去看看EventBus中所有的public方法,无非都是一些状态判断,获取事件,移除事件的方法;没什么好介绍的,基本见名知意。


好了,到此我们的源码解析就结束了,希望大家不仅能够了解这些优秀框架的内部机理,更能够体会到这些框架的很多细节之处,并发的处理,很多地方,为什么它这么做等等。


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics