简介
为了简化并且高效在Activity
、Fragment
、Thread
、Service
等组件之间的通信,且进一步解耦,事件总线应运而生,我们简单介绍其中的EventBus
。
EventBus
是一款针对安卓优化的发布-订阅事件总线。开销小,代码简洁,方便组件与线程、组件间的通信以及发送者与接受者解耦。比如说,Fragment
之间的通信,要么需要Activity
作为媒介,要么需要Broadcast
作为媒介,效率不高,而且难以传递实体类数据。而EventBus就能很好解决这一问题。
EventBus三要素
- Event :
事件
,可以是任意类型的对象。 - Subscriber:
事件订阅者
。在EventBus3.0
之后,事件处理的方法可以随便取名,但是需要添加注解@Subscribe
,并且需要指定线程模型(默认POSTING
)。模型有五种 ,下面会说。 - Pulisher:
事件发布者
,可以在任意线程模型、位置发送事件,直接调用EventBus的post(Object)
。根据post函数参数的类型,会自动调用订阅相应类型事件函数。(可以自己实例化EventBus对象,但一般使用EventBus.getDefault() 获得一个同步的DCL单例对象)
五种线程模型
- POSTING (默认):事件在那个线程发出来,就在那个线程运行。避免在此类型的事件中执行耗时操作,因为它会阻塞事件的传递,甚至会引起ANR。
- MAIN : 事件处理会在UI线程中执行。不要执行耗时操作。
- BACKGROUND:如果事件是在主线程发送的,事件处理函数会在新的线程中执行。如果是在子线程,则继用此线程,不新建。不要在函数内对UI进行操作。
- ASYNC : 发布事件一律新建一个线程中执行,不要在函数内对UI进行操作。
- MAIN_ORDERED: 在Android上,订阅者将在Android的主线程(UI线程)中被调用。与MAIN不同的是,事件将始终排队等待交付。这确保了post调用是非阻塞的。
使用方法
- 配置gradle:
implementation 'org.greenrobot:eventbus:3.3.1'
- 定义消息事件类:
data class Message(var msg : String = "")
- 注册和取消注册事件
class MainActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
val scrollView = ScrollView(this)
with(LinearLayout(this))
{
orientation = LinearLayout.VERTICAL
addView(Button(this@MainActivity).apply {
text = "进入新界面"
setOnClickListener {
startActivity(Intent(this@MainActivity, SecondActivity::class.java))
}
})
addView(Button(this@MainActivity).apply {
text = "注册事件"
setOnClickListener {
// 注册事件
EventBus.getDefault().register(this@MainActivity)
}
})
scrollView.addView(this)
}
setContentView(scrollView)
}
override fun onDestroy()
{
super.onDestroy()
// 取消注册事件
EventBus.getDefault().unregister(this)
}
}
- 事件订阅者处理事件
在MainActivity
自定义方法处理事件,在这里将ThreadMode(线程模型)
设置为MAIN,事件处理会在UI线程执行,用Toast
展示:
@Subscribe(threadMode = ThreadMode.MAIN)
fun lexerEvent(message: Message)
{
Toast.makeText(this, message.msg, Toast.LENGTH_LONG).show()
}
- 事件发布者发布事件
class SecondActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(Button(this).apply {
text = "发送事件"
setOnClickListener {
EventBus.getDefault().post(Message("Hello, This is a message!"))
finish()
}
})
}
}
- 使用方法也简单,先点击 “注册事件” ,在跳转到SecondActivity,点击“发送事件”,这样返回到MainActivity也就有Toast输出了。
EventBus 的黏性事件
所谓黏性事件,就是发送事件后再订阅该事件也能收到该事件,这和黏性广播类似。
我们在MainActivity写一个方法处理:
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
fun lexerStickyEvent(message: Message)
{
Toast.makeText(this, message.msg, Toast.LENGTH_LONG).show()
}
在SecondActivity加入按钮发送黏性事件,注意是postSticky:
class SecondActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
addView(Button(this@SecondActivity).apply {
text = "发送事件"
setOnClickListener {
EventBus.getDefault().post(Message("Hello, This is a message!"))
finish()
}
})
addView(Button(this@SecondActivity).apply {
text = "发送黏性事件"
setOnClickListener {
EventBus.getDefault().postSticky(Message("Hello, This is a sticky message!"))
finish()
}
})
})
}
}
使用方法是,先进入SecondActivity,点击“发送黏性事件”,返回到MainActivity后,再点击“注册事件”就能成功显示。
这是MainActivity
的代码:
class MainActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
val scrollView = ScrollView(this)
with(LinearLayout(this))
{
orientation = LinearLayout.VERTICAL
addView(Button(this@MainActivity).apply {
text = "进入新界面"
setOnClickListener {
startActivity(Intent(this@MainActivity, SecondActivity::class.java))
}
})
addView(Button(this@MainActivity).apply {
text = "注册事件"
setOnClickListener {
// 注册事件
EventBus.getDefault().register(this@MainActivity)
}
})
scrollView.addView(this)
}
setContentView(scrollView)
}
override fun onDestroy()
{
super.onDestroy()
// 取消注册事件
EventBus.getDefault().unregister(this)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun lexerEvent(message: Message)
{
Toast.makeText(this, message.msg, Toast.LENGTH_LONG).show()
}
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
fun lexerStickyEvent(message: Message)
{
Toast.makeText(this, message.msg, Toast.LENGTH_LONG).show()
}
}
data class Message(var msg : String = "")
小结
EventBus
入门是非常容易的,这里不做过多介绍,有兴趣可以自行查阅源码,也可以看其他博主的详细解读。