事件总线。继承自观察者模式,事件总线也是基于发布订阅的机制来实现事件的发送和接受的。
为何要使用
Android 应用开发过程中,经常会涉及Activity,Fragment,Service等不同组件或者模块间的消息传递,使用传统的方法实现,往往会写出丑陋的代码,而且不同组件和模块之间耦合严重,随着模块的日益增多,代码逻辑的不断新增和修改,整个代码的架构就会显得越来越混乱,一个模块的改动可能会引起其他模块的连锁反应。为了便于理解,下面举例说明:
1 Activity中不同的Fragment之间需要通信,传统的做法是将Activity作为中介,FragmentA 通过getActivity()获取宿主Activity 实例进而可以拿到FragmentB的实例,从而向FragmentB 发送消息或者获取数据,好一点的做法是在Fragment中编写接口,让宿主Activity实现该接口,从而在Activity中实现不同Fragment之间的数据通信。
为了解决以上问题,实现组件间和模块间的解耦,我们引入了事件总线的概念
原理
事件总线,顾名思义,是消息或者说事件流动的管道,不同组件和模块之间的消息传递都是通过总线来实现,组件与组件,模块与模块之间不直接进行通信,一言以蔽之,事件总线就是用来简化Android应用中组件或者模块化的通信,从而实现模块间解耦的目的
事件总线是基于观察者模式的思想实现的,它使用发布订阅的方式支持组件和模块间的通信,摒弃了观察者模式需要显示注册回调的缺点,同事可以用于替换Java中传统的事件监听方式。事件总线涉及到的关联方式如下:
1 事件Event:一个普通的POJO类,只包含数据,不包括对数据的操作,事件有两种类型:普通事件和粘滞事件,粘滞事件的特点实在事件发布后,订阅者才开始订阅该类型事件,那么它依然可以收到这个事件,而普通事件是收不到的
2 订阅者Subscriber:订阅某种类型事件的对象,通常会有一个回调函数用于对接收到的事件进行处理,订阅者可以订阅事件,也可以取消订阅的事件,订阅者可以引入优先级的概念。优先级高的订阅者可以优先接收到该事件,并可以决定是否继续传递事件给低优先级的订阅者。
3 发布者Publisher: 事件的源头,发布某种类型事件的对象
4 总线EventBus:负责订阅者,事件等信息的存储,同时处理事件的流动和分发,通过总线,订阅者和发布者是解耦的,互相不知道对方的存在。
事件总线的总体架构可以借用EventBus这个库的官网截图
开源实现
Android事件总线的开源实现有很多,例如Google出品的Guava库中就包含了一个EventBus模式,但由于Guava库很庞大,为了避免引入太多无用代码,一般都不建议使用这个库,最使用广泛的主要有greenrobot的EventBus,square的otto。
EventBus
EventBus是一个专门为Android 平台优化定制的事件总线函数库,处于性能考虑,没有使用Java注解,因为在Android平台上,查询注解是很慢的,尤其是在Android 4.0之前的系统上。
Android Studio$Gradle中使用EventBus只需要如下几个步骤
在build.gradle中添加在线依赖如下
定义事件类
注册事件订阅者,在处理事件的类的合适位置进行事件的订阅和取消订阅,同时实现名为onEvent的回调函数:
在任何一个类中,如果产生了某个事件,那么可以通过如下代码进行事件的发布,这样订阅者就可以收到这个事件的广播了
Event基于性能考虑没有使用注解,而是使用“名称约定优于配置”的思想,导致的缺点如下:
1 接受事件的函数必须以onEvent开头
2 一般每个事件对应一个Event类,会产生很多样本类,从而增加APP出现64K方法数问题的可能
3 用于接受EventBus事件的类不能混淆,否则会找不到onEvent函数
Otto
otto是在Guava的EventBus模块基础上针对Android 平台增强定制的事件总线函数库,和greenrobot的EventBus最大的不同是它使用运行时注解的方式,在性能上较EventBus差,但使用上比EventBus灵活,同时功能方面相比EventBus也少了很多特性,从EventBus的官网可以看到,无论从功能特性还是性能,EventBus都比otto优秀。
otto已经标记为过时了,将不再提供新功能和特性,推荐使用RxJava来代替它,当然,RxJava虽然和事件总线同样都是基于观察者模式实现的,但功能不仅相同,事件总线主要适合组件和模块化通信使用,而RxJava的使用场景更多的是异步数据流的处理,基于函数响应式编程方式
与观察者模式及Android广播的区别
虽然可以使用Android 的BroadcastReceiver来实现各种事件的监听,但它更适合用于监听Android 系统级的广播事件,例如网络状态变化,电量变化,对于业务相关的事件变化,使用BroadcastReceiver太重量级了,而且使用起来也很不方便,最贱实践应该是把BroadcastReceiver限定于监听系统级别的广播事件。
观察者模式用于简单的事件监听没有问题,但如果APP全局都使用观察者模式来解决组件和模块间的消息通信,那么可能会造成接口膨胀的问题,观察者模式要求开发者自己实现事件的生成,分发和处理,需要进行很好的设计,同时,观察者模式不支持粘滞事件,不支持事件优先级等特性,当然,性能上来说,观察者模式要比事件总线性能高,比较它不需要处理很多其他的特性
事件总线使用起来很方便,但我们不应该滥用它,需要严格限定它的使用范围,只要在组件或者模块间通信时才使用它,对于简单的消息传递,就选用观察者模式或者事件回调的方式即可
网友评论