EvenBus是一个广为使用的android开源库,用来作为事件通知和触发响应,集合了观察者模式和命令模式,可以很好的扩展以及解耦,是很好用的android库。
现在项目的代码就用到了这个库,做了一些简单的封装。
最近工作中发现了自己的一个认识误区:以前一直以为如果是在和eventBus同一个线程post一个event, 那么一定会同步的执行注册了此event的所有响应,
不过在实践中却发现并非如此:
EventBus中对于投递一个event在同一个线程的情况,在进行投递时,会首先判断一个threadLocal变量,看当前线程是否正在投递(isPosting变量标示),触发注册此event的响应, 如果isPosting, 那么就直接将此event object放入到 ThreadLocal的一个queue, 然后直接返回, 如果不是isPosting, 那么会从event queue中依次取出所有的没有被投递的event,进行相应的投递响应.
从这里看,明显的,绝对不是一个同步的操作,
而我遇到的场景是这样的:
<1> event1被触发(EventBus.post(event1)), 然后开始执行其响应 A(),
<2> 而在A()里面会触发event2(EventBus.post(event2)),而event2()也会开始投递到其响应函数B(),
<3> 但是因为isPosting, 因此将event2放入此线程的eventBus queue, 然后直接返回.
<4> A()执行完了, event1的投递响应到此结束,
<5>虽然event1的投递已经完成, 但是event queue的队列又多了一个event2(之前放入的),那么开始处理event2的响应,执行B().
从这个过程就可以看到,执行链条是这样的: event1 -> A() begin -> event2 ->A() end -> B() begin -> B() end.
而我一开始认为的是 event1 -> A() begin -> event2 -> B() begin - > B() end -> A() end.
绝对不是一个同步执行返回的结果,这样认为会导致很多的时序性问题。
一开始分析的时候,看log,没想到A()还会触发EventBus.Post, 还以为是多线程,后来打了threadId,发现是同一个线程,差点以为出bug了,后来关键点打了下stackTrace, 才搞清楚, 唉,功力不够。