关于Android EventBus源码随记

315 阅读4分钟

EventBus通过订阅用户来在activity,fragment,service以及一些控件之间进行消息的传递。代替原生的handler,Broadcast,intent, 以及自定义的一些interface接口进行轻量化的传递。

首先通过getDefault完成实例化EventBus。default使用volatile修饰,应该是防止多线程之间的使用问题。

实例化完成后,通过register完成对当前activity,fragment或者控件的注册,添加一个subscriber,默认不具有黏连性。

这里可以看到注册的subscriber会在subscriberMethodFinder中去寻找,如果不存在会添加进去。 register 函数中会先根据订阅者类名去subscriberMethodFinder 中查找当前订阅者所有事件响应函数,然后循环每一个事件响应函数,依次执行subscribe 函数 此处需要记录的是 subscriberMethodFinder:用于记录当前订阅者所有事件的响应函数 subscriptionsByEventType:每个事件所有订阅者信息,根据优先级保存订阅者信息队列中 typesBySubscriber: 保存当前订阅者所有事件

到了订阅的方法,根据SubscriberMethod中eventType来在subscriptionsByEventType中寻找是否有订阅信息,不存在就put到改map中,存在则抛出异常提示已经存在。 值得注意的地方是:

这里会根据你添加的订阅信息的优先级与原本存在的订阅列表中的订阅信息进行优先级的比较,根据优先级的高低来对订阅列表信息中的订阅信息进行排序。如果此处是具有粘连性消息则立即分发。

这里注册订阅完成以后,就可以通过EventBus.getDefault().post(event);来进行事件的分发了

首先会将event消息保存在一个list中,下面会进行判断消息是否发出,如果未发出并且消息列表不为空时
将消息发送出去,发送消息主要是通过postSingleEvent方法进行的,该方法中对消息事件进行了缓存处理,然后通过postSingleEventForEventType方法进行事件的发送,下面看下改该方法进行了什么样的操作:

该方法会根据当前的消息类型找到所有的订阅者,并且通过
该方法继续下发消息。 postToSubscription(Subscription subscription, Object event, boolean isMainThread)方法是所有消息发送的地方,黏连性消息也是通过改方法进行发送。

此处不同线程的判断,是当时通过@Subscribe订阅的时候线程参数为依据。 @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true, priority = 100) 参数中可以有线程,是否具有黏连性,以及优先级的判断。

postToSubscription 函数中会判断订阅者的 ThreadMode,从而决定在什么 Mode 下执行事件响应函数。ThreadMode 共有四类:

PostThread:默认的 ThreadMode,表示在执行 Post 操作的线程直接调用订阅者的事件响应方法,不论该线程是否为主线程(UI 线程)。当该线程为主线程时,响应方法中不能有耗时操作,否则有卡主线程的风险。适用场景:对于是否在主线程执行无要求,但若 Post 线程为主线程,不能耗时的操作; MainThread:在主线程中执行响应方法。如果发布线程就是主线程,则直接调用订阅者的事件响应方法,否则通过主线程的 Handler 发送消息在主线程中处理——调用订阅者的事件响应函数。显然,MainThread类的方法也不能有耗时操作,以避免卡主线程。适用场景:必须在主线程执行的操作; BackgroundThread:在后台线程中执行响应方法。如果发布线程不是主线程,则直接调用订阅者的事件响应函数,否则启动唯一的后台线程去处理。由于后台线程是唯一的,当事件超过一个的时候,它们会被放在队列中依次执行,因此该类响应方法虽然没有PostThread类和MainThread类方法对性能敏感,但最好不要有重度耗时的操作或太频繁的轻度耗时操作,以造成其他操作等待。适用场景:操作轻微耗时且不会过于频繁,即一般的耗时操作都可以放在这里; Async:不论发布线程是否为主线程,都使用一个空闲线程来处理。和BackgroundThread不同的是,Async类的所有线程是相互独立的,因此不会出现卡线程的问题。适用场景:长耗时操作,例如网络访问。

最后一步就是解除订阅unregister() 通过typesBySubscriber来取出这个subscriber订阅者订阅类型,从typesBySubscriber移除该subscriber,后续事件发送就不会找到改订阅者信息。

这是本人第一次写笔记,由于很多东西看了就忘记了,所以打算通过这样的方法进行记录所学,由于水平有限对源码看的不是很透彻,这里特别感谢JangGwa的文章,对应源码再看一遍很有帮助,如有写的有问题的地方希望指正,谢谢大家。 参考:https://www.jianshu.com/p/d1cb4ecd357f