对于事件总线的概念,我们最初接触的可能要属Handler了,然后Handler使用起来些许的麻烦另很多人不爽(包括我);于是就产生了更多好用的工具,EventBus就是这其中大家最喜欢的一个,EventBus拥有一系列的方法:register、unregister、post、onMessageEvent等。EventBus因为其用法非常的简洁却又不失强大的功能,深受许多开发者的喜爱。EventBus的定位是事件总线,我们就先来了解一下事件总线这个概念。
原理
我们想要实现事件总线,那么首先需要了解什么是事件总线及其实现原理;这个东东好抽象怎么去理解呢,那我们就扒一扒EventBus的源码吧(两个关键过程register、post):
register注册:可以看出这个方法很简单,找出注册者所有的注册的方法,然后调用下个方法
EventBus register()方法源码subscribe订阅:先判断是否订阅过,没有订阅过的话就把订阅者及其订阅的事件保存到typesBySubscriber中,通过查看我们可知typesBySubscriber是Map<Object,List<Class<?>>>类型的,其中key是订阅者,value是订阅者所订阅的所有事件类型的集合。
EventBus subscribe源码,忽略.sticky的内容以上就是注册的大部分内容了,道理很简单,将订阅者及订阅的方法及订阅的事件类型都保存到一个位置。
post发射:做了一系列判断,我们忽略这些,然后调用postSingleEvent
EventBus post源码postSingleEvent:先过滤事件类型,然后继续下个方法
EventBus postSingleEvent源码postSingleEventForEventType:又做了一系列关于订阅状态的判断,然后调用下个方法
EventBus postSingleEventForEventType源码postToSubscription:根据订阅方法的线程设置,调用不同方法,这里只看主线程的调用
EventBus postToSubscription源码invokeSubscriber:通过反射调用了订阅的方法。
EventBus invokeSubscriber源码分析一下发射的过程:当发射一个事件数据的时候,根据事件类型找到订阅了这个类型的订阅者及其订阅的方法,然后通过反射调用这个方法。
看了这一堆的源码,事件总线还是挺简单的嘛。
通过简单的分析EventBus的源码我们对事件总线是什么东东有了一个总体的概念,也对如何实现事件总线有了方向:将订阅者的信息统一保存在某个位置,当有数据发送的时候,根据订阅者所订阅的事件类型找到需要被通知的订阅者,然后调用其相关方法。
实现
本人在开发中极少用到EventBus,大多情况下在用功能更为强大的rxjava,这两者都是基于观察者模式的。
现在我们就用rxjava实现实现一种最基本的bus,这几行代码是不是太简洁了点:
事件总线的rx简单实现使用的时候也非常简单:
事件总线的rx简单应用有人说,人家EventBus不是这样的吖,很多高人的RxBus也不是这样写的啊,你怎么register还返回一个被观察者呢,你这也没有把订阅者集中管理啊。
我这里想说一下自己的意见:rxjava拥有一堆强大的操作符,如果按照EventBus那种方法封装的话,会牺牲掉太多的灵活性,比如常用的map、flatmap、observeOn、subscribeOn;反而register返回一个被观察者,不但省掉了unregister方法,而且你想要怎么操作不都很随意了么......
如果你真的需要做成EventBus那样,只需模仿EventBus增加一个Map变量,然后register方法增加一个参数并返回void,再增加一个unregister方法不就齐活了么......
对于EventBus的postSticky,也非常简单,只需将PublishSubject换成ReplaySubject就行了:
用于sticky的ReplaySubject至于原因,就贴一下ReplaySubject的注释好了:
ReplaySubject的源码官方注释如果你有其他特殊的需求,那就自己定制吧,比如利用特殊功能的BehaviorSubject、PublishProcessor等等。
总结:
事件总线,只要弄懂了其原理,不管是用起来还是实现起来都非常的简单。
但是这个东东,有许多人将其奉为神物,也有许多人对它非常抵制。
优点:解耦彻底、语法简洁;
缺点:代码中你要不一一对应的写具体注释,维护的时候恐怕就搞不清逻辑关系了。
以上的对比说明事件总线是一把双刃剑,当然任何东西都有长有短,在实际开发中我们还需了解这些特性后再根据项目的需求进行合理的取舍,而不是一味的抬高或抛弃!
网友评论