EventBus源码解析

EventBus作为一个事件处理分发总线框架,如今被广泛用于大大小小的企业之中。其能够如此之火,一定有它的特别之处。今天就来分析一下EventBus的原理。

1、定义事件

EventBus源码解析_第1张图片

 

2、注册、注销与发送事件

EventBus源码解析_第2张图片

 

3、设置响应函数

EventBus源码解析_第3张图片

 

ThreadMode

EventBus共包括4种模式:

  • POSTING:在post所在线程执行
  • MAIN:在主线程(UI thread)中执行
  • BACKGROUND:在后台线程中执行,适合耗时短的处理
  • ASYNC:在单独线程中执行,适合耗时较长的处理

粘性事件
特点是不需要先订阅,就是在发送事件之后再订阅该事件也能收到该事件。例如已经发送了一个粘性事件,这时候再打开一个新的Activity或者Fragment,并在其中订阅了EventBus的消息,那么这个时候,粘性事件能够收到,而普通事件无法收到。

同一类型(消息类)的粘性事件只会保存一个,如果有多个一起发生,则只会保存最后一个类型的粘性事件
 

 

 

EventBus使用方法还是蛮简单的,下面让我们来看一看它的原理。

EventBus源码解析_第4张图片

 

上图是发送事件时的post代码。

可以看到会获取到一个当前post线程状态的类。从里面获取一个事件队列,把事件添加到队列中。

接着会判断当前线程队列是否在发送事件,如果没有,则会把当前线程队列设置为post状态,并且把是否是主线程状态进行赋值。

接着会判断当前队列是否被取消,如果没有,则通过while循环,不断地把队列里每个事件都发送出去,每发送一个就移除一个,直到队列数量为0。

EventBus源码解析_第5张图片

那么让我们来看一看,消息队列的持有者currentPostingThreadState是什么。

EventBus源码解析_第6张图片

它是一个ThreadLocal,里面持有的类型是PostingThreadState。

可以看到里面的内容大致为上面说到的那几个。

这里也可以看出,当你post一个事件时,掌管这个事件的事件队列,被ThreadLocal的形式为每一个线程进行了管理。

EventBus源码解析_第7张图片

之后再来看上面提到的队列循环里取事件发送的代码。

EventBus源码解析_第8张图片

第一个难懂的地方,是这个lookupAllEventTypes。

假如事件为Message.class。这个方法,是把这个类当做key,为它保存了它,已经它的所有父类,以及与他相关的所有接口。这些统一放到了一个List里。

EventBus源码解析_第9张图片

subscriptionByEventType是一个map,以事件类为key,CopyOnWriteArrayList为value。保存了这个类相关的所有订阅信息。

EventBus源码解析_第10张图片

而这个Subscription,里面持有了一个subscriber以及subscriberMethod。

这里盲猜subscriber实际上就是你所绑定时的Activity或Fragment。

而SubscriberMethod则是在Activity或Fragment中所有使用到该类并用Suscribe注解的方法。

这里需要注意,存放的维度是以事件为维度,将Activity或Fragment与方法绑定。

EventBus源码解析_第11张图片

而SubscriberMethod里则保存了真正的方法,线程模式,事件类型,优先级以及是否是粘性事件。

EventBus源码解析_第12张图片

postToSubscription方法则是真正意义上的发送事件方法。

我们看到会对订阅类里的线程模式进行判断与不同的处理。

而对于不同的线程,每个都有一个自己的事件队列,如果当前线程不满足线程条件,则会被分配到对应的线程队列里去。

EventBus源码解析_第13张图片

这个invokeSubscriber方法是最后调用我们处理事件的方法。

invoke方法包含了两个参数,第一个就是我们之前猜测的方法的持有者activity或fragment,而第二个参数正是我们处理方法所需要的参数也就是我们定义的事件类。

看到这不得不说,EventBus设计的真好。能够想到以这样的方式把Activity,事件,处理方法联系起来。

最后作者还有一个疑问,就是粘性事件是怎么工作的。

EventBus源码解析_第14张图片

在postStickyEvent里,只比post方法多了一步,就是把事件放到了粘性事件集合中。这个集合是一个以事件类class为key,事件为value的map。这也就是为什么粘性事件发送时,只能负责触发最新的。因为之前的都被覆盖了。

而这个粘性事件集合在subscribe方法中被用到了。

其实想一下也能大概猜到,当一个activity被激活,完成事件订阅后,就会触发粘性事件。那么一定是在这里完成的。

这个订阅方法里面主要完成的就是订阅者主体与方法的绑定,同时我们看到了优先级的处理方式。当当前方法的优先级高于当前i值对应的方法优先级时,则在i的位置插入此方法,其他优先级低的事件则后移。若遍历到最后,当前方法优先级仍然是最高的,则在最后一个位置后面插入,也就是数组整体大小+1。

保存每个事件订阅内容集合的是一个CopyOnWriteArrayList,它是一个线程安全的ArrayList。适合于读多写少的场景。不能保持实时的更新。写的时候会复制出一个新的容器,往新的容器里添加元素,之后把指针指向新的容器。而读还是读的老数据,实现了读写分离。

最后,在判断此方法是否是粘性事件后,会进行一个checkPostStickyEventToSubscription操作。

这个方法的里面,调用了postToSubscription方法,实现了最终事件处理。

最后的最后,要搞清楚subscribe方法是在什么时机调用的。

EventBus源码解析_第15张图片

啊哈,最后在这里看到了我们想要的答案。

也就是这一切的一切,都从register的那一刻,开始了。

 

 

 

 

 

 

 

 

你可能感兴趣的:(Android面试)