Android EventBus粘性事件实现机制探究
众所周知,eventbus是支持粘性事件的,即可以先发送粘性事件,然后再注册,代码如下:粘性事件观察者@subscribe(threadmode = threadmode.main, sticky =
众所周知,eventbus是支持粘性事件的,即可以先发送粘性事件,然后再注册,代码如下:
- 粘性事件观察者
@subscribe(threadmode = threadmode.main, sticky = true)
fun registereventbus(o: any) {
}
- 发送粘性事件
eventbus.getdefault().poststicky(any())
- 注册eventbus
eventbus.getdefault().register(this)
接下来我们就来探究下eventbus的粘性事件是如何实现的。
poststicky()内部机制

- 如果是发送的粘性事件,会添加到
stickyevents
中,看下这个属性的实现:

可以看到这个属性是一个map集合,其中key为事件类型的class对象,value为对应的事件类型。
- 继续看下
post(event)
方法:

-
首先将这个粘性事件添加到
postingthreadstate
(线程私有)的eventqueue
集合中 -
通过
ismainthread
方法判断当前是否为主线程,最终会调用到我们熟悉的looper.getmainlooper() == looper.mylooper()
进行判断 -
循环遍历
eventqueue
队列,不断的取出集合元素进行分发,看下postsinleevent()
方法如何实现:

-
如果
eventinheritance
为true,会查找当前发送的粘性事件类型的父类型,并返回查找到的集合 -
接下来就会调用
postsingleeventforeventtype()
方法来进行最终粘性事件的分发,即通知通过@subscribe
注解注册的粘性事件观察者,看下具体实现:

- 调用
subscriptionsbyeventtype
获取注册该事件类型的所有订阅方法,但是由于这个时候我们是先发送的粘性事件再注册eventbus
,而subscriptionsbyeventtype
中集合元素的填充实在注册eventbus
发生的,所以通过subscriptionsbyeventtype
获取到的subscriptions
将是null的,所以接下来肯定不会走下面的if代码块中的逻辑了。
poststicky()小结
上面这么多代码逻辑,其实只干了一件事,就是将这个粘性事件添加到了stickyevents
这个集合中。之后的逻辑虽多,但和粘性事件没啥关系。
register内部机制

-
findsubscribermethods()
这个方法里面的逻辑就不带大家进行分析了,总之就干了一件事情:
查找当前类通过
@subscribe
注册的所有事件订阅方法,并返回一个list<subscribermethod>
集合,其中subscribermethod
就是对每个注册的订阅方法和当前注册类的封装
-
subscribe
这个方法是关键,深入探究下:


-
第1、2、3、4步中其实就干了两件事情:
- 填充
subscriptionsbyeventtype
集合,key为事件类型,value为通过@subscribe
订阅了该事件类型的方法集合 - 填充
typesbysubscriber
集合,key为注册eventbus的类,value为该类中所有@subscribe
注解修饰的方法集合
- 填充
-
第5步就是实现粘性事件分发的关键地方
- 首先判断当前
@subscribe
修饰的订阅方法是否为粘性,即@subscribe(sticky = true)
中sticky
等于true - 是的话就从
stickyevents
集合中判断是否存在和订阅方法中注册的事件类型相同的事件:
这个
stickyevents
是不是很熟悉,就是我们之前发送粘性事件时,将粘性事件添加到的方法集合- 如果存在,则就执行该粘性事件的分发,即调用执行该订阅方法,最终会调用到
invokesubscriber()
方法:
- 首先判断当前

从上面可以看到,最终是通过反射来实现的订阅了粘性事件方法的执行。
register小结
该方法最终会判断当前是否存在注册eventbus
前发送的粘性事件,且当前注册类中存在订阅该事件类型的方法,然后立即执行。
总结
以上就是eventbus
粘性事件的内部实现机制,总体来说不算复杂,大家看着文章跟着源码一步步分析应该就很容易理解这部分实现逻辑了。
网友评论