EventBus这个开源框架出来已经很久了,深的很多开发者青睐,由greenrobot组织贡献(该组织还贡献了greenDAO),是一个Android事件发布/订阅轻量级框架,通过解耦发布者和订阅者简化Android事件传递,EventBus可以代替Android传统的Intent,Handler,Broadcast或接口函数,在Fragment,Activity,Service线程之间传递数据,执行方法。
其最大的特点就是:代码简洁,是一种发布订阅设计模式(观察者设计模式)。在没有EventBus之前我们通常用广播来实现监听,或者自定义接口函数回调,但有的场景我们也可以直接用Intent携带简单数据,或者在线程之间通过Handler处理消息传递。但无论是广播还是Handler机制远远不能满足我们高效的开发,广播是四大组件之一,许多系统级的事件都是通过广播来通知的,比如说网络的变化、电量的变化,短信发送和接收的状态,但是广播是相对消耗时间和资源的,Handler虽然简单但高复发的内存泄漏困扰很多初级开发者,那么EventBus会很好消除这些缺点,那么本节我们来了解一下他的使用方法,很简单的哦,相信以后你也会爱上的。
EventBus3.0源码地址:https://github.com/greenrobot/EventBus
EventBus重要方法和类:
Event 传递的事件对象
Subscriber 事件的订阅者
Publisher 事件的发布者
ThreadMode 定义函数在何种线程中执行
他们之间的关系如图:
那么具体该怎么操作呢? 请往下看
1)在需要订阅事件的地方注册事件,可以是Activity或者Fragment中
EventBus.getDefault().register(this@MainActivity)
2)创建Event消息类 —定义事件模型
该类可以不继承任何基类也不需要实现任何接口,
class MessageEvent(val progress: Int)
这里我用Kotlin写的,所以大家看起来会有些不习惯,不过相信大家看起来不会有问题,因为android的api是不变得,只是kotlin写法稍有改变,会java的同学学起Kotlin也会很容易,由于Google现在墙裂推荐Kotlin,作为Android开发者还是不能掉队,所以大家有时间也多尝试这门小众语言,继续我们的内容,
3)产生事件、发送事件
EventBus.getDefault().post(MessageEvent(time))
在我们需要传递消息的地方将数据封装到消息类Event中发送出去,这里我们就将数据发送出去了,我们怎么接受这条消息呢? 接着看
4)消费事件,处理消息
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMessage(event: MessageEvent) {
progress!!.progress = event.progress
}
@Subscribr()注解标识我们的线程模型,这里我们要更新进度条的进度,所以制定消费事件的线程为主线程,在3.0之前,EventBus还没有使用注解方式。消息处理的方法也只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,分别代表四种线程模型。而在3.0之后,消息处理的方法可以任意命名,这是个很大方便,但是需要添加一个注解@Subscribe,并且要指定线程模型(默认为PostThread),需要注意的是事件处理函数的访问权限必须为public,否则会报异常。
这里我们更新UI中进度条进度,大家可以在此取出消息内容执行自己的逻辑。
当然,我们要记得取消订阅,跟广播逻辑很相似。
override fun onDestroy() {
super.onDestroy()
EventBus.getDefault().unregister(this@MainActivity)
}
回到上面话题线程模型处,我们来了解这几个线程模型具体含义:
在EventBus的事件处理函数中需要指定线程模型,即指定事件处理函数运行所在的想线程。在上面我们已经接触到了EventBus的四种线程模型。那他们有什么区别呢?在EventBus中的观察者通常有四种线程模型,分别是PostThread(默认)、MainThread、BackgroundThread与Async。
PostThread:如果使用事件处理函数指定了线程模型为PostThread,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。在线程模型为PostThread的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
MainThread:如果使用事件处理函数指定了线程模型为MainThread,那么不论事件是在哪个线程中发布出来的,该事件处理函数都会在UI线程中执行。该方法可以用来更新UI,但是不能处理耗时操作。
BackgroundThread:如果使用事件处理函数指定了线程模型为BackgroundThread,那么如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
Async:如果使用事件处理函数指定了线程模型为Async,那么无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行。同样,此事件处理函数中禁止进行UI更新操作。
EventBus黏性事件:
EventBus除了普通事件也支持粘性事件,这个有点类似广播分类中的粘性广播。本身粘性广播用的就比较少,为了方便理解成订阅在发布事件之后,但同样可以收到事件。订阅/解除订阅和普通事件一样,但是处理订阅函数有所不同,需要注解中添加sticky
= true,
findViewById(R.id.button).setOnClickListener {
Thread(Runnable {
time = 0
while (time <= 100) {
EventBus.getDefault().postSticky(MessageEvent(time))
SystemClock.sleep(500)
time += 10
} }).start()
EventBus.getDefault().register(this@MainActivity)
//粘性事件,在需要的时候注册,接受最后一条消息
}
//EventBus.getDefault().register(this@MainActivity)
}
这里我们没有在onCreate()中注册EventBus,我们是收不到广播的,其实这里我们可以另外添加一个按钮,在按钮点击事件里面注册EventBus,我们这里把注册这一步放在发送事件的后面,也可以按照刚才说的那种方式把注册步骤放到另外一个button点击事件里面。
对于粘性广播我们都比较清楚属于常驻广播,对于EventBus粘性事件也类似,我们如果不再需要该粘性事件我们可以移除
EventBus.getDefault().removeStickyEvent(MessageEvent(time))
或者调用移除所有粘性事件
EventBus.getDefault().removeAllStickyEvents();
如果对粘性事件还不是很熟悉的同学可以再去看看广播的内容,也可以将广播内容跟EventBus做个总结,设计思想及其相似,都是基于观察者模式,只是粘性体现在能够收到订阅之前发送的消息。但是它只能收到最新的一次消息,比如说在未订阅之前已经发送了多条黏性消息了,然后再订阅只能收到最近的一条消息。
看到这里,你是不是对EventBus已经有了很好的了解,EventBus使用很简单,但是确实给项目和开发者带来很大的方便,有机会大家可以尝试看看EventBus的源码,从源码角度更深层次了解EventBus的强大,本节就到这儿,我们下次再见!!! 晚安