Android探索与巩固(Kotlin下的EventBus)
- 前言
- EventBus三要素
- ThreadMode
- EventBus用法示例
- 效果示例
- 最后总结
前言
EventBus是一款针对Android优化的发布/订阅事件总线,用于简化各组件间,组件和线程的通信。原生是用广播来实现,用广播的话效率不高,而且数据必须是实体类。所以EventBus用的会比较多,他可以将发送者与接收者解耦,代码看起来也比较整洁。之前看了刘望舒大神的博客1来学习,下面就总结一下基本用法。
EventBus三要素
EventBus主要有三个元素组成:
- 事件(Event),是一个对象可以是任意数据类型。
- 事件订阅者(Subscriber),EventBus3.0之后,事件处理的方法可以自由命名,在使用它时需要在方法上面添加一个注解@Subscribe,并写明采用哪种线程模式,默认为POSTING。
- 事件发布者(Publisher),可以用它在任意位置发送事件,需要调用post方法实例化EventBus对象,然后根据破石头函数的参数类型,自动调用订阅这个事件的函数。
ThreadMode
EventBus3.0有四种线程模式:
- POSTING(默认模式):当事件处理的方法指定了默认模式,那么事件就会在发出事件的线程中运行,这样结果就是发送和接收在同一个线程中。所以这种模式下方法处理要避免耗时比较长的操作,在它运行期间会阻塞事件的传递,最坏的结果就是引起ANR(Application Not Responding)。
- MAIN:事件处理会放在主线程(UI线程)中运行,所以同上,处理事件不能过长,不慎也会引起ANR。
- BACKGROUND:这个模式下,如果事件在UI线程中发布出来,那么会将此事件移到一个新创立的线程中,如果在子线程中发布,则在发布事件的线程中运行。因为这个模式不允许在UI线程中运行,所以这个模式不能进行有关于UI的操作。
- ASYNC:无论事件在哪个线程中发布,都会把事件移到新创立的子线程中运行,同上,无法进行UI操作。
EventBus用法示例
这里的示例我用了自己的基类和类ARouter的路由通信,基本大同小异,只需要注意EventBus的用法就好。
- 在项目的build.gradle中添加配置:
implementation 'org.greenrobot:eventbus:3.1.1'
- 添加消息事件类:
class MessageEvent internal constructor(message: String) {
private var message: String? = null
init {
this.message = message
}
internal fun getMessage(): String? {
return message
}
fun setMessage(message: String) {
this.message = message
}
}
- 事件的注册和取消订阅
class EventBusActivity : BaseActivity<BasePresenter>(){
val Tag = "EventBusActivity"
override fun initWidgets() {
tv_message.text = getString(R.string.EventBusActivity)
btn_subscription.text = getString(R.string.subscriptionEvent)
btn_message.text = getString(R.string.jumpToSecond)
}
override fun setListeners() {
click(btn_message,btn_subscription)
}
override fun onWidgetsClick(v: View) {
when(v){
//RegisteredEvent
btn_subscription ->{
if (!EventBus.getDefault().isRegistered(this)){
EventBus.getDefault().register(this)
}else{
showToast(getString(R.string.repeatRegistration))
}
}
btn_message ->{
goActivity(Paths.DemoPage.SecondActivity)
}
}
}
override fun bindLayout() = R.layout.activity_eventbus
override fun onDestroy() {
super.onDestroy()
//取消注册事件
EventBus.getDefault().unregister(this)
}
- 事件订阅者处理事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun Event(messageEvent: MessageEvent) {
tv_message.text = messageEvent.getMessage()
}
- 发布事件
class SecondActivity :BaseActivity<BasePresenter>(){
override fun initWidgets() {
tv_message.text = getString(R.string.SecondActivity)
btn_subscription.text = getString(R.string.sendStickyEvents)
btn_message.text = getString(R.string.sendEvent)
}
override fun setListeners() {
click(btn_message,btn_subscription)
}
override fun onWidgetsClick(v: View) {
when(v){
btn_message ->{
EventBus.getDefault().post(MessageEvent(getString(R.string.wish)))
finish()
}
btn_subscription ->{ EventBus.getDefault().postSticky(MessageEvent(getString(R.string.stickyEvents)))
finish()
}
}
}
override fun bindLayout() = R.layout.activity_eventbus
}
- 粘性事件
EventBus的粘性事件与粘性广播类似,就是发送了事件之后再次订阅该事件也能收到。
@Subscribe(sticky = true)
fun StickyEvent(messageEvent: MessageEvent) {
tv_message.text = messageEvent.getMessage()
}
订阅粘性事件与上面相同,发送粘性事件在上面的代码中有。
效果示例
主页,显示EventBusActivity,我们首先订阅事件。然后跳转到SecondActivity发送事件。
点击发送事件
接下来测试粘性事件,首先我们先不订阅事件,先跳转到SecondActivity,点击发送粘性事件。然后我们发现字样并没有变化。
这个时候我们订阅事件,会发现字样改变。
最后总结
EventBus基本用法就是先建立消息事件类,然后注册事件,在Activity中注意最后要取消订阅。然后建立事件订阅者处理事件,要注意线程模式。最后通过事件发布者发布事件,一般使用 EventBus.getDefault().post()发布。如果遇到在发布事件后还没有注册事件的情况,就使用粘性事件处理。
用法详解就到这里了,作为一个渴求真相的小程序员,我在之后还要继续在原理上探索EventBus是如何实现的,到时候如果有什么心得也会随时记录。这是我第一次总结第三方框架使用,如有不妥欢迎指正。另外我的个人总结demo已经同步更新了,如果博文有不详细的地方可以通过demo进一步理解。
- EventBus3.0用法全解析 ↩︎