统计时间 2023.4.30
最后版本更新时间 2021.12.8
version 3.3.1
star 24.3k
1.EventBus 的使用场景
2.EventBus 和 BroadcastReceiver 的区别?
3.EventBus 中使用了那些设计模式?
4.EventBus 的注意事项?
5.EventBus 的实现原理?
6.EventBus 的粘性事件是如何实现的?
EventBus 简介
EventBus 是用于 Android 和 Java 的事件总线。
简化了 Activity, Fragment, Thread, Service等之间的通信。
● 解耦事件发送者和接收者(基于观察者的特性)
● 避免复杂且容易出错的依赖关系和生命周期问题
可以设置订阅者的优先级 和 交付的线程
代码更少,质量更好。
使用场景
1.消息通知
比如在详情页面有个数据被点赞了,同步到 列表页面也需要更新
2.组件之间传递较大数据,Intent 会有1MB的限制
通过 Intent 不能传递大数据,会被 Binder 的大小所限制。这时候可以用 EventBus 代替
3.组件化之间的通信
基础使用
1.添加依赖到 build.gradle
implementation 'org.greenrobot:eventbus:3.3.1'
2.定义事件
class MessageEvent
3.准备订阅者
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
Log.d("yhblock", "EventBus register")
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
Log.d("yhblock", "EventBus unregister")
}
@Subscribe
fun onMessageEvent(event: MessageEvent) {
Log.d("yhblock", "onMessageEvent: " + Thread.currentThread().name)
}
4.发布事件
EventBus.getDefault().post(MessageEvent())
指定订阅者的线程
在订阅者的方法中,有些操作可能必须在主线程进行,这时候可以通过 @Subscribe 中的 threadMode 指定方法的执行线程。
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: MessageEvent) {
Log.d("yhblock", "onMessageEvent: " + Thread.currentThread().name)
}
ThreadMode.POSTING(默认)
会运行在和发布者同一个线程中,不会进行线程切换,没有切换线程的开销。
适合已知的可以在很短时间内完成而不需要主线程的简单任务
ThreadMode.MAIN
如果发布者不在主线程,则会切换到主线程。如果发布者在主线程,和 ThreadMode.POSTING 一样进行处理。
适合操作一定要在主线程的任务,比如更新主线程的 UI。
ThreadMode.MAIN_ORDERED
订阅者将在Android的主线程中被调用。事件总是排队等待稍后交付给订阅者,因此对post的调用将立即返回。这为事件处理提供了更严格和更一致的顺序(因此命名为MAIN_ORDERED)。例如,如果你以主线程模式在事件处理程序中发布另一个事件,第二个事件处理程序将在第一个事件处理程序之前完成(因为它是同步调用的-将其与方法调用进行比较)。对于MAIN_ORDERED,第一个事件处理程序将完成,然后第二个事件处理程序将在稍后的时间点(只要主线程有容量)被调用。
使用此模式的事件处理程序必须快速返回,以避免阻塞主线程。
ThreadMode.BACKGROUND
如果发布者在主线程,会切换到后台线程处理。如果发布者在后台线程,会直接在当前线程处理任务。
适合在后台线程执行的短时间任务
ThreadMode: ASYNC
会单独开启线程
适合像网络请求等在后台执行的耗时操作任务
粘性事件
有时候事件会在订阅之前就发送了,这时候再订阅就会收不到之前的数据了,为了保证可以接收到数据,可以设置数据为粘性。
1.接收粘性事件
@Subscribe(sticky = true)
fun onMessageStickyEvent(event: MessageStickyEvent){
Log.d("yhblock", "onMessageStickyEvent: " + Thread.currentThread().name)
}
2.发送粘性事件
EventBus.getDefault().postSticky(MessageStickyEvent())
粘性事件是在 EventBus 在当前类注册的时候发送的
EventBus pre register
onMessageStickyEvent: main
EventBus register
注意事项
1.慎用 EventBus
除非大数据传输,状态更新同步等特色场景,其他情况最好不要使用 EventBus,将这个作为最后的方案。因为EventBus的观察者太过于灵活,对于代码的可维护性造成了不少问题。增加了代码的复杂度,特别是接手其他开发者的项目时,太痛苦了
2.粘性事件需要及时取消
3.避免重复注册和取消注册
//注册
if(!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this)
}
//取消注册
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this)
}
使用建议
1.通过 Lifecycle 关联 EventBus 的生命周期,减少 Activity 中的代码
class LifecycleEventBus : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(owner)
}
super.onStart(owner)
}
override fun onStop(owner: LifecycleOwner) {
super.onStop(owner)
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(owner)
}
}
}
class MainActivity : AppCompatActivity() {
private val lifecycleEventBus = LifecycleEventBus()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
lifecycle.addObserver(lifecycleEventBus)
}
}
2.使用统一的 Event,减少 Event 类的数量
data class CommonEvent(val eventId: Int)