EventBus 源码笔记(1)

来源:互联网 发布:知乎 餐馆 编辑:程序博客网 时间:2024/04/29 07:26
  1. EventBus ThreadMode:

    1. PostThread: Subscriber的calback和post在一个线程,默认设置. 这样可以减少线程切换的开销,也是对于比较简单的需求的推荐设置. EventHandler中的Callback不建议执行blocking很长时间的操作,因为有可能callback会在主线程上执行.
    2. MainThread: 所有Subscriber的callback都会运行在MainThread, 如果post所在的Thread就是MainThread, 那么callback会被马上执行.
    3. BackgroundThread: 所有Subscriber的callback都会运行在nonMainThread, 如果post所在的线程不是主线程,那么callback会被马上执行,如果post是发生在MainThread,那么EventBus会专门有一个后台线程来序列化的deliver所有的这类callback.
    4. Async: 所有Subscriber的callback都会运行在一个单独的线程,这个线程及不是mainThread也不要是post所在的nonMainThread. 在使用这个模式的时候,要避免同时触发了大量的长时间运行的thread.EventBus也维护了一个线程池来进行高效的线程复用。
  2. 和很多的开源库一样,EventBus的构造采用了Builder模式, 不过相对来说选项比较少: EventBusBuilder

    1. logSubscriberExceptions: default true.
    2. logNoSubscriberMessages: default true.
    3. sendSubscriberExceptionEvent: default true.
    4. sendNoSubscriberEvent: default true.
    5. throwSubscriberException: default false.
    6. eventInheritance: 这个选项指是EventBus是否要考虑Event之间的继承关系(如父类的EventHandler可以收到子类的event), 默认是打开的,如果关掉,对于简单的继承关系,可以提升大概20%的deliver效率, 越复杂的越好。当然了,因为本身post event占的工作量很少,所以建议在只有post非常频繁的时候才关掉这个.
    7. executorService: 为 async/background 提供一个自定义的线程池,否则就是Builder自己的一个static的newCachedThreadPool.
    8. skipMethodVerificationFor: 这个可以禁用对于制定的Class中的onEvent()方法的名字以及modifer的检查.
    9. installDefaultEventBus(): 返回一个默认的EventBus实例(EventBus.defaultInstance). 注意这是一个单例, 并且可以多线程获取, 采用了lazy-init.
  3. EventBus类:

    1. getDefault(): 和Builder中的installDefaultEventBus()目的一致, 不会有冲突.
    2. 构造函数可以接受一个EventBusBuilder(自行指定或者使用提供的DEFAULT_BUILDER), 构造过程中除了根据builder来设置一些信息外,还new了几个Poster以及几个Map 和 一个subscriberMethodFinder(构造时使用了builder的skipMethodVerificationForClasses).
    3. register(…)函数: 最终会接受3个参数:
      1. Object subscriber: 不解释.
      2. boolean sticky: 和post sticky相对应, 会将最近的sticky event投递出去. 这里的sticky的意思类似与pending,在Subscriber unregister的这段时间,有对应的event发生, 那么就会被存储为一个sticky event, 注意这里应该是只保留最近一次的.
      3. int priority: 就是event投递时的优先顺序,越大越早得到event.
    4. register(…)的实现: 首先根据SubScriber(传进去的已经是一个Object了)的Class类型,通过subscriberMethodFinder从中提取出一堆SubscriberMethod(就是调用者自己定义的callback)(List<SubscriberMethod>), 然后遍历得到的SubscriberMethod, 调用subscribe(subscriber, subscriberMethod, sticky, priority).
    5. subscribe函数:
      • 获取SubscriberMethod的eventType
      • 然后获取对应于eventType的Subscription list(这里是一个CopyOnWriteArrayList)
      • 根据subscriber/subscriberMethod/priority来构造一个newSubscription.
      • 如果之前的到的SubscriptionList是空的,那么这里就需要new一个,然后放在subscriptionsByEventType这个map中.
      • 如果发现SubscriptionList中已经contain了newSubscription, 那么说明出现了重复的register, 会抛异常.
      • 否则就按照priority将newSubscription加入到SubscriptionList中合适的位置上去.
      • 还要将subscriber和eventType建立其对应(typesBySubscriber保存这个对应关系: Map<Object, List<Class<?>>>)
      • 最后会专门针对sticky进行处理:
        • 如果需要考虑event的继承关系:
          • 那么当前所有的继承自event的stickyEvent都应该被考虑, 这里会遍历整个stickyEvents(Set<Map.Entry<Class<?>, Object>>), 获取读应的Class然后使用isAssignableFrom来进行判断,满足的条件的event会被通过checkPostStickyEventToSubscription(…)传递出去.
        • 如果不需要考虑event的继承关系:
          • 很简单,直接根据eventType取出对应的stickyEvent然后投递即可.
    6. checkPostStickyEventToSubscription(…) -> postToSubscription(…)
    7. isRegistered(Object subscriber): 检查某个subscriber是否已经register过了.
    8. unregister(Object subscriber): 从typesBySubscriber中获取对应的subscribedTypes, 然后挨个的unubscribeByEventType(…), 并从typesBySubscriber中remove(…). 如果之前就没有register,那么会抛一个异常.
    9. post(Object event):
      • 因为会设计到多线程,首先获得当前线程的TLS: PostingThreadState.
      • 进一步获得当前postingState的eventQueue,然后将要post的event加入到eventQueue中.
      • 如果postingState表明现在没有在posting(isPosting), 先判断下现在是不是在主线程, 将isPosting标记为true. 如果发现postingState已经被cancel掉了(postingState.canceled), 那么抛出一个异常.
      • 否则对eventQueue进行遍历: 挨个取出event并且调用 postSingleEvent(eventQueue.remove(0), postingState), finally中会将isPosting/isMainThread设置为false.
    10. postSingleEvent(Object event, PostingThreadState postingState):
      • 获取event的Class类型.
      • 如果制定了要考虑event之间的继承关系, 那么显然需要对每种符合条件的event类型进行post.
      • 如果不需要,那么就只调用postSingleEventForEventType(event, postingState, eventClass)即可.
      • 还要考虑没有找到可以deliver的对象情况,如果指定了sendNoSubscriberEvent并且eventClass也不是NoSubscriberEvent/SubscriberExceptionEvent,那么还会post一个NoSubscriberEvent(this, event)出去进行一次力所能及的通知.
    11. postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass):
      • 根据eventClass从subscriptionsByEventType中获得对应的subscriptions List.
      • 然后遍历subscriptions List, 调用postToSubscription(subscription, event, postingState.isMainThread)
      • 每次postToSubscription(…)后都会check postingState.canceled, 如果被aborted, 那么显然就不需要再继续post了,直接退出了.
    12. postToSubscription(Subscription subscription, Object event, boolean isMainThread):
      • 根据subscription的subscriberMethod的threadMode进行不同的逻辑处理:
        1. PostThread: invokeSubscriber(subscription, event), 不解释,在哪个线程post的就在哪个线程callback.
        2. MainThread: 根据当前在的是否是mainThread来invokeSubscriber(…)/mainThreadPoster.enqueue(..)
        3. BackgroundThread: 如果当前所在的是mainThread, 那么将task投递到backgroundThread中(backgroundPoster), 否则直接invokeSubscriber(..)
        4. Async: 一律enqueue到asyncPoster中.
        5. default, 不可能,直接抛异常.
    13. invokeSubscriber(Subscription subscription, Object event):
      • 调用subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
      • 会catch InvocationTargetException并做特殊处理.
      • 如果是IllegalAccessException,那么会rethrow一个 new IllegalStateException(“Unexpected exception”, e).
    14. Subscription是怎么生成的: subscribe(…)中根据subscriber/subscriberMethod/priority new出来的. 那么可以看到关键是subscriberMethod是怎么生成的, 是通过subscriberMethodFinder.findSubscriberMethods(subscriber.getClass())来得到的:

      • SubscriberMethodFinder’s findSubscriberMethods(Class<?> subscriberClass): 其实就是很简单的反射遍历:
      • 首先去methodCache中查找一遍(speedup). 如果找到一个不为null的List<SubscriberMethod>,直接返回即可.
      • cache没有就老老实实的反射找吧, 会一直遍历到继承树的最上面.
      • class.getName(), 首先那些以”java.”, “javax.”, “android.”开头的类就不必继续check了,直接break.
      • 否则获取class的getDeclaredMethods(), 遍历所有的Method:
        • 获取method的name, 首先确认methodName是以”onEvent”开头的, 然后获取method的modifier, 首先必须是public的method, 并且也不是指定的要忽略的modfier: MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC.
        • 然后获取method的参数类型表, 只对参数数量为1的进行继续处理.
        • 然后截取methodName (“onEvent”)后面的部分:
          1. 如果后面没有更多内容,那么ThreadMode就是PostThread, 2. “MainThread”
          2. “BackgroundThread”
          3. “Async”
          4. 对于其他情况,如果发生了,再确认一下这个class是不是在skipMethodVerificationForClasses中,如果也不在,那么就throw exception.
        • 接下来根据paramType[0]和methodName生成一个对应该方法的key,并存在eventTypesFound, 如果之前没有这个,那么根据相关信息生成一个SubscriberMethod对象并添加到subscriberMethods中.
        • 最后check subscriberMethods,如果发现是空的,那么throw exception, 否则会将subscriberMethods 以 subscriberClass.getName() 作为key放入到methodCache中, 最后返回subscriberMethods.
    15. Subscription这个概念其实就是一个Subscriber + Subscriber所生明的一个subscriberMethod, 描述的是订阅关系 这种关系对象,其实就是命令模式中的command. 其equals为true的标准是Subscriber一样(同一个Object),method 之间equal.

    16. SubscriberMethod本身就是一个infoholder,存储了对应的method/threadMode/eventType, 纳闷的是为啥不直接把方法的执行集成为这个类的函数,反而是外部调用直接拿到method对象进行invoke

    17. AsyncPoster的work流程:

      • 其实从EventBus中对AsyncPoster以及AsyncPoster本身的定位来看,这货应该是作为一个单例类存在的,但是不知道为啥没整成这样.
      • EventBus本身维护了一个asyncPoster变量,初始化的时候就new了一个AsyncPoster.
      • 调用的是asyncPoster.enqueue(subscription, event).
      • 真正的调用流程比较纠结: enqueue本身发生在主线程,显然不会在这里就执行,那么必然的,会将task放到一个队列中,这个队列就是asyncPoster内部的一个Queue, 加新的task放到queue以后,肯定不会自己动起来,需要主动的调用eventBus.getExecutorService()(这个Executor被指定由background/Async使用).execute(*this), 注意是this, 因为asyncPoster本身就是一个Runnable.
      • 那么实际在NoMainThread发生的必然是这个run函数了,其内容也很简单,首先肯定要把task从queue中poll出来,如果没有,判定为一个exception. 因为已经在NoMainThread了,可以放手执行真正的work了: eventBus.invokeSubscriber(pendingPost), 这里的pendingPost其实就是封装的Task信息(比如subscription/event啥的)
      • AsyncPoster绕的一点就在与它自己实现了Runable,如果有一个别的Runnable类,就很明了了.
    18. BackgroundPoster和AsyncPoster基本一致:

      • 多了一个executorRunning标识eventBus.getExecutorService()现在是不是在干活, 在enqueue的时候,会检查是不是running,如果没在跑,会eventBus.getExecutorService().execute(this) + executorRunning = true 把自己schedule起来.
      • run函数不是one-shot了,而是一个while(true), poll则加了一个1000ms参数(PendingPostQueue实现的,就是wait罢了), 如果取到了Task, 那么就直接执行,如果没有取到, 会同步一次this**再次尝试提取poll()(应该是考虑race condition, 即当前有人获取了lock并且正在添加task,那么在这边获取lock之后,就能够拿到这个刚刚添加的Task**), 如果还是null, 那么就不浪费时间精力了,return并将executorRunning设置为false,如果poll(1000)被打断,那也没有办法,也会退出while(true), finally 兜底将executorRunning设置为false, 有点不明白为什么和AsyncPoster不同. 这两者在post 任务到后台线程时应该表现是一致的.
0 0