图解EventBus源码

观察者模式和订阅发布模式预览

开局一张图,故事全靠编。(看不见水印,看不见水印,看不见水印)

1.EventBus源于订阅发布模式。

在订阅发布模式(上图右)中,发布者和订阅着互相不感知对方的存在,双方通过消息代理进行通信,各组件间松耦合。Eventbus的作用正如上图的EventChannel,它提供的功能更是一种总线机制,甚至可以说是路由机制。发布者将消息发布到总线Eventbus上,剩下的工作交有Eventbus来处理。订阅者被EventBus持有和维护,EventBus将消息一一发布给订阅者。正因此,我们项目中,一版可以显示找到订阅者入activity,但是发布者则隐藏于各种,随处都可以是发布者,随处都可以post出来消息。

而在观察者模式(上图左)中,观察者和被观察者没有完全解耦,抽象被观察者持有抽象观察者,并维护观察者列表。与订阅模式相当于在观察者和被观察者之间架了一层,由这个中间层来持有观察者,这样被观察者无须感知观察者。

订阅发布模式
观察者模式
EventBus核心结构

2.register过程

image5.png

通过findSubscriberMethods查找回来一个包含订阅者所有订阅方法的订阅列表。跟进findSubscriberMethods如何查找。

image6.png

通过运行时反射遍历查找

image7.png
image8.png

如果设置了索引加速,通过索引查找。原理是EventBusAnnotationProcessor。

image9.png

找打订阅方法后,开始进行一系列的存储操作

image10.png
image11.png

如果是黏性属性的方法,则立即去缓存黏性事件的stickyEvents查找是否有黏性事件,有则立即post到当前订阅者里执行,且只有当前订阅者会执行一次,其他地方不会执行,也没有查找订阅者这一过程。

register小结

register过程
核心数据结构

3.post过程

image14.png
image15.png
image16.png
image17.png

ThreaMode说明

PostThread:默认的 ThreadMode,表示在执行 Post 操作的线程直接调用订阅者的事件响应方法(哪个线程post出来就在哪个线程中执行),不论该线程是否为主线程(UI 线程)。当该线程为主线程时,响应方法中不能有耗时操作,否则有卡主线程的风险。适用场景:对于是否在主线程执行无要求,但若 Post 线程为主线程,不能耗时的操作;

MainThread:在主线程中执行响应方法。如果发布线程就是主线程,则直接调用订阅者的事件响应方法,否则通过主线程的 Handler 发送消息在主线程中处理——调用订阅者的事件响应函数。显然,MainThread类的方法也不能有耗时操作,以避免卡主线程。适用场景:必须在主线程执行的操作;

BackgroundThread:在后台线程中执行响应方法。如果发布线程不是主线程,则直接调用订阅者的事件响应函数,否则启动唯一的后台线程去处理。由于后台线程是唯一的,当事件超过一个的时候,它们会被放在队列中依次执行,因此该类响应方法虽然没有PostThread类和MainThread类方法对性能敏感,但最好不要有重度耗时的操作或太频繁的轻度耗时操作,以造成其他操作等待。适用场景:操作轻微耗时且不会过于频繁,即一般的耗时操作都可以放在这里;

Async:不论发布线程是否为主线程,都使用一个空闲线程来处理。和BackgroundThread不同的是,Async类的所有线程是相互独立的,因此不会出现卡线程的问题。适用场景:长耗时操作,例如网络访问。

再来看看黏性事件的post过程

image18.png

注意看,这里有个加锁的过程,为什么postSticky需要加锁,而post不需要加锁?因为postSticky的事件会先存储到Map<Class<?>, Object> stickyEvents中,而stickyEvents是EventBus全局只有一个

,也就是所有的黏性事件都存储在这个map中,故当不同线程同时poststicky事件的时候存在并发问题。而普通的post出来的事件,都是存储在线程的本地变量的事件队列里,各线程互不干扰互相不能访问对方的数据,故不存在并发问题。

post小结

post过程
image20.png

ThreadLocal:线程用来存储私有变量(一个很有意思的东西)

名义上以ThreadLocalMap变量形式在线程内部,但是底层实现是基于Entry[]数组而不是HashMap。(这里引发一个思考,为什么要用数组实现,其实数组也可以称一种map,用数组实现开放定址法处理冲突,

用数组存储key和value更节省内存,普通的HashMap是拉链法解决冲突,基于数组和链表,每个Entry元素除了key和value还要一个Entry类型的next指针,占用更多内存。同样的思想也在Android的sparseArray和ArrayMap中使用。)

Entry{

Object key; // key实际上是我们定义的ThreadLocal对象,而非当前线程对象

Object value;

}

image21.png

4.unregister

image22.png
image23.png
image24.png

5思考&总结

优点:

1.事件总线通信,使用简单

2.解耦,干脆利落

缺点:

1.极致的解耦导致项目维护和阅读难度增大,出现EventBus满天飞的场景

2.更甚者,它使我们往往懒于去代码中找寻设计的快感

3.如果不及时unregister则会内存泄露

关于性能:

1.EventBus3.0以前大量使用反射,存在性能瓶颈,3.0以后引入APT(注解处理器)后在编译期解析注解,性能飙升

2.EventBus在每次查找到订阅者和其绑定的订阅方法集合后会放在Map里缓存。(这是注解框架的一贯套路,Butterknife亦如是)

参考文章:
http://www.cnblogs.com/bugly/p/5475034.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容