前文
由于EventBus的源码还是比较的复杂的,打算使用五篇文章从浅入深的分析它的源码。包括:
最佳实践
包括一些方法的使用解释,建议的实用配置方案,以及最后梳理一下整个EventBus的整体架构加深理解。
常用方法
是否注册
boolean isRegistered(Object subscriber)
subscriber是否注册了
起效后续时间传递
void cancelEventDelivery(Object event)
,取消后续的事件传递,比如我们需要某个事件假如已经被某个地方接收了就不需要往后传递,则可以使用这个方法,我们可以再回看下post的
流程,在post方法中,这里就可以更加清楚post的流程了
1 | public void post(Object event) { |
然后我们再看cancelEventDelivery
1 | public void cancelEventDelivery(Object event) { |
通过源码我们得知假如需要取消事件的传递:
- 发起取消的线程需要与
post
的线程是同一个,否则currentPostingThreadState
就直接对不上了 - 事件需要没有分发完成,isPosting只有在
post()
方法整体执行完成之后才会设置为true
- 取消的事件必须是当前分发的事件,
event
字段他是在postSingleEventForEventType
里面赋值的,在调用postToSubscription
之前到调用完成之后都是同一个,在postToSubscription
之后才会设置为空 - 订阅方法的
threadMode
需要为POSTING
,而默认的也是POSTING
我们一般取消订阅的方式可以给订阅方法设置优先级priority
,值越大优先级就越高,那么我们就可以在高优先级的订阅方法接收到之后终止后续事件传递,当前也可以按照我们的需求,某个订阅方法接收到了之后就可以不继续往下传递。
是否有订阅者
boolean hasSubscriberForEvent(Class<?> eventClass)
,某个事件是否有被订阅,注意,假如他的父类是有被订阅的,也会返回true。比如有一个订阅方法test(Foo f)
,然后Child
是Foo
的子类,然后使用Child
的class去调用hasSubscriberForEvent
会返回true,无论配置的eventInheritance
否为true。
清除缓存
clearCaches
清除所有的method
缓存和eventTypesCache
缓存。
线程调度
我们都知道订阅方法可以通过设置threadMode
来决定在那个线程接收到消息,具体的分发我们看postToSubscription
方法,处理POSTING
是没有进行线程切换,即post
那个线程,接收就那个线程,其他都是有通过Poster
进行切换的。我们就详细看下这块的逻辑。
Poster接口的定义
1 | public interface Poster { |
首先我们看下MAIN
模式
1 | if (isMainThread) { |
HandlerPoster的主要逻辑
1 |
|
MAIN_ORDERED
模式:与Main
模式不一致,优先使用mainThreadPoster,否则再去使用当前的线程
1 | if (mainThreadPoster != null) { |
BACKGROUND
模式:如果是主线程就使用backgroundPoster,否则就在当前线程。
1 | if (isMainThread) { |
BackgroundPoster的代码分析:
1 | final class BackgroundPoster implements Runnable, Poster { |
ASYNC
模式:不管是否是子线程,直接新的线程去执行
1 | asyncPoster.enqueue(subscription, event); |
AsyncPoster分析:
1 | class AsyncPoster implements Runnable, Poster { |
总体回归
首先,我们再来回归下EventBus
的一些关键的成员变量,之前没有怎么细说。
defaultInstance
,默认的EventBus.getDefault()
返回的EventBus实例,一般不推荐使用这个DEFAULT_BUILDER
,defaultInstance
配置eventTypesCache
,缓存了一个map,key为类class,value对应他自己的class,父类的class,自己的接口,父类的所有接口的集合,可以用于快速查找在post(obj)
中的obj事件需要通知的订阅方法。subscriptionsByEventType
,一个map,key为事件的类型,value为该事件需要通知的方法列表(单个由Subscription包裹),他会在unregister
的时候清除掉属于当前subscriber的订阅方法,他的用途有两个:hasSubscriberForEvent
方法中,安排到你某个事件是否有订阅者postSingleEventForEventType
,找到某个事件对应的订阅方法,然后调用该方法
typesBySubscriber
,是一个map,key为订阅者,value为订阅事件,即记录了当前订阅者他的所有的订阅方法
推荐配置和使用规范
我们使用EventBus,建议都使用EventBusBuilder去构建EventBus对象,而不是使用默认的,EventBusBuilder的属性和默认值如下
1 | boolean logSubscriberExceptions = true; //是否大于订阅相关的异常 |
看完了EventBusBuilder
,然后我们就开始说下比较合适的配置:
- 需要开启注解模式,具体可以看EventBus3.x源码解析-register流程分析(注解方式)
- 自己封装一层EventBus,推荐如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46object MyBus {
private val eventBus = EventBus.builder()
.logSubscriberExceptions(isDebug) //debug的时候开启
.logNoSubscriberMessages(isDebug) //debug的时候开启
.sendNoSubscriberEvent(isDebug) //debug的时候开启
.throwSubscriberException(isDebug) //debug的时候开启
.eventInheritance(false)
.addIndex(AIndex) //所有的注解类集合
.addIndex(BIndex) //所有的注解类集合
.logger(object : Logger {
override fun log(level: Level?, msg: String?) {
//使用自己的log类打印日志,这样可以避免release打印日志
}
override fun log(level: Level?, msg: String?, th: Throwable?) {
//使用自己的log类打印日志,这样可以避免release打印日志
}
})
.build()
fun register(subscriber: Any) {
eventBus.register(subscriber)
}
fun unregister(subscriber: Any) {
eventBus.unregister(subscriber)
}
fun post(event: Any) {
eventBus.post(event)
}
fun removeStickyEvent(event: Any): Boolean {
return eventBus.removeStickyEvent(event)
}
fun <T> removeStickyEvent(eventType: Class<T>?): T? {
return eventBus.removeStickyEvent(eventType)
}
fun postSticky(event: Any) {
eventBus.postSticky(event)
}
...
}
我们后续就直接调用MyBus
类
其他的点:
关于post的消息对象,应该是需要统一成一个对象类,而不是多种类型的obj,比如,我们应该定义一种通用的event,后续所有的消息都post这个event。
1
data class Event(val type: String, val data: Any? = null)
这样的好处就是可以一个页面可以统一处理所有的事件,通过type区分,通过data取值
关于继承事件的问题,就是子类重写了父类的方法
- 子类使用了
@Subscribe
父类没有,子类也没有super父类,那么父类不会收到消息 - 父类使用了
@Subscribe
子类没有,也是子类的方法收到消息,如果子类没有super父类也不会收到消息 - 子类与父类同时使用了
@Subscribe
,这种方式是不建议的,可能会运行错误,运行正确的时候也是之类能收到,父类的需要看子类是否有super。
所以我是建议eventInheritance
设置为false,当我们的父类有@Subscribe
的时候,子类直接override并且super,也不需要使用@Subscribe
注解。
- 子类使用了