`
苗振忠
  • 浏览: 56655 次
  • 性别: 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方法,无非都是一些状态判断,获取事件,移除事件的方法;没什么好介绍的,基本见名知意。


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


分享到:
评论

相关推荐

    eventbus-3.0.0 jar包及源代码下载

    eventbus-3.0.0 jar包及源代码下载;eventbus-3.0.0 jar包及源代码下载;eventbus-3.0.0 jar包及源代码下载;eventbus-3.0.0 jar包及源代码下载

    eventbus-3.0.0.jar+eventbus-3.0.0-sources.jar

    EventBus 是一个流行于 Android 开发中的发布/订阅事件总线库,由 ...在 "eventbus-3.0.0.jar+eventbus-3.0.0-sources.jar" 中,你将获得 EventBus 最新版本的功能和源码,有助于深入理解和使用这个强大的工具。

    android eventbus-3.2.0.jar

    android eventbus-3.2.0.jar 解压就可以使用

    eventbus-3.1.1.jar

    "eventbus-3.1.1.jar" 文件是 EventBus 的一个特定版本,版本号为 3.1.1,通常包含该库的 Java 类和资源,用于集成到 Android 项目中。 在 EventBus 中,事件(Event)是通过发布(Posting)和订阅(Subscribing)...

    Go-EventBus-Go轻量级事件总线兼容异步

    在`EventBus-master`这个压缩包中,包含了Go-EventBus的源代码和示例。首先,我们需要导入库: ```go import "github.com/gocraft/event" ``` 然后,创建一个事件总线实例: ```go bus := event.New() ``` 接...

    eventbus-3.0.0.jar

    在 "eventbus-3.0.0.jar" 文件中,包含了 EventBus 的这个特定版本的所有类和资源,使得开发者可以在项目中方便地引入和使用 EventBus。 1. **事件总线概念**:EventBus 是一种设计模式,它将事件发布者和事件订阅...

    eventbus-2.1.0-beta-1.jar

    总的来说,EventBus-2.1.0-beta-1.jar 是一个强大的 Android 事件通信库,它通过简化组件间通信,提高了代码的可读性和可维护性。理解并熟练使用 EventBus,可以极大地提升 Android 应用的开发效率和质量。

    eventBus-3.1.1.jar

    "eventBus-3.1.1.jar"是EventBus库的一个特定版本,包含所有必要的类和资源,便于开发者将其集成到他们的项目中。 在Android开发中,通常我们需要在不同的组件(如Activity、Fragment或Service)之间传递信息。传统...

    安卓 EventBus 使用示例 eventbus-3.1.1.jar

    安卓 EventBus 使用示例,开发工具为eclipse+ADT,EventBus可简化安卓各个组件,线程之间的通信 相关博客 http://blog.csdn.net/qq_34763699/article/details/79467327

    EventBus-master.zip项目安卓应用源码下载

    EventBus-master.zip项目安卓应用源码下载EventBus-master.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考

    Weiz.EventBus-master.zip

    【标题】"Weiz.EventBus-master.zip" 是一个与 .NET 框架相关的压缩包,其中包含了 Weiz.EventBus 的示例代码。这个库是一个事件总线(Event Bus)实现,用于在应用程序的不同组件之间传递事件,促进松耦合和更好的...

    Android应用源码之EventBus-master.zip项目安卓应用源码下载

    Android应用源码之EventBus-master.zip项目安卓应用源码下载Android应用源码之EventBus-master.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考

    EventBus-jar包

    本文将深入探讨 EventBus 的核心概念、工作原理以及如何在实际项目中应用。 ### 核心概念 1. **发布者(Publishers)**:发布者是事件的来源,当某个事件发生时,发布者会通过 EventBus 发布事件。发布者通常是...

    Android代码-EventBus-Apt

    compile 'com.shizhefei:eventbus-api:1.2.1' //eventbus 注解 compile 'com.shizhefei:eventbus-annotation:1.2.1' 在定义Event接口的Module添加,以便于生成Event接口的代理 annotationProcessor '...

    EventBus-iOS.zip

    EventBus-iOS是一个针对iOS...总的来说,EventBus-iOS提供了一种在iOS应用中实现事件驱动编程的有效方式,通过理解和运用这个框架,开发者可以更好地组织代码结构,减少组件间的耦合,提高系统的可维护性和可扩展性。

    netflix-eventbus-0.3.0.jar

    netflix-eventbus-0.3.0.jar

    EventBus-3.0.1.jar

    EventBus最新的jar包,2016-5-10

    Android应用源码之EventBus-master_应用.zip

    EventBus 是一个流行的 Android 事件总线库,它简化了应用程序内部组件之间的通信。相比于传统的回调或静态方法,EventBus 提供了一种订阅发布模式,使得组件之间可以通过发布事件来传递消息,而无需显式地调用接口...

Global site tag (gtag.js) - Google Analytics