EventBus非常好用,可以说直接把开发中的数据通信方式从飞鸽传书带到了打电话模式。那么,这么神奇的框架它是怎么把事件交到接收者手中的呢。
看一下post方法,它是从ThreadLocal类型的final常量currentPostingThreadState中取出事件队列,然后将要发送的事件添加到队列中,然后在while循环中进入到postSingleEvent方法去发送事件。
这里大概解释一下ThreadLocal,该类主要用于存储线程的私有变量。在其内部,实际是使用一个属于线程的map映射,key就是当前ThreadLocal本身,value则是要保存的值。如下,
接下来看看postSingleEvent方法,eventInheritance默认为true,然后在lookupAllEventTypes去获取注册了该事件的所有类,包括接口,在循环中把事件给到postSingleEventForEventType方法去处理,若subscriptionFound为false,则表明没有任何类注册了接受该事件。
再看postSingleEventForEventType方法,仍然是将事件给到了关键的发送方法postToSubscription去处理。我们直接看postToSubscription,
在这个方法中,首先判断了订阅方法的threadMode类型,threadMode就是编写订阅方法时设置的,分为 MAIN,POSTING,BACKGROUND,ASYNC四种。MAIN比较常用,MAIN类型的订阅者是主线程;POSTING的订阅者是当前线程;BACKGROUND的订阅者是在子线程;而ASYNC模式特殊,发送出去的事件都会开启新线程接受处理。
可以看到,POSTING模式直接调用了invokeSubscriber方法,眼熟吗,没错,他就是采用了反射的方式;看一下这个方法内部,
直接反射调用了订阅方法。
MAIN模式,如果是发送事件也在主线程,那么直接也采用反射,如果是在子线程,这个mainThreadPoster实际是一个handler,并且是一个属于主线程的handler,看下图,
也即是说在子线程中发送的事件交给了handler去处理,怎么处理的呢。看看enqueue方法,
首先,获取了一个包含事件及其订阅者的封装类PendingPost,并且PendingPost内部是复用模式,并没有频繁创建新对象这种占据大量内存的操作。它维护了一个保存PendingPost的集合,并且加了同步锁,保证了线程安全性。看下图,
接下来,回到enqueue方法中(图1),在同步锁的保护下,将PendingPost添加到了PendingPostQueue队列中,sendMessage方法启动消息循环,并且就在本handler自己的handmessage方法中,从PendingPostQueue队列中poll出PendingPost消息对象,并且在同步锁和非同步锁两种情况下判断若取出的PendingPost为空,那handler则回到未激活状态,不再从队列中取消息。
最关键的一步,eventBus.invokeSubscriber(pendingPost),没错,还是反射。因为这个时候事件已经从发送线程交给了订阅者所在的线程,继续采用反射调用订阅方法。所以handler作用是起到了一个快递运输的作用,把事件搬运到订阅者线程。如下图,
以上是MAIN模式下的处理方式,相反的,BACKGROUND模式下,若发送线程也是在当前子线程,则直接反射调用,若不是,也是使用handler,此时的handler是属于子线程的handler罢了。
ASYNC模式不常用,它是在新线程中处理事件,并且最后也是调用了反射。
这里用到了ExecutorService这种优于 new Thread的方式来创建线程,且其内部默认使用线程池来管理线程。
本次的浅析到此为止。