Android 消息发布订阅框架:EventBus

目录

1.是什么
2.如何使用
3.五种线程模型
4.Eventbus2和Eventbus3的区别

一、是什么

EventBus是一款发布/订阅事件总线的框架,使用它可以进行模块间通信、解耦。它可以使用很少的代码,来实现多组件之间的通信,非常的方便。

为什么使用它呢?以前一直在用广播来实现,但是广播使用起来较为麻烦且效率不高,当项目变大以后,就会变得特别复杂。LiveData也可以进行数据的订阅和发布,但是不能处理复杂的情况。我们可以使用EventBus。

EventBus是一种用于Android平台上的事件发布/订阅框架,它允许不同的组件之间进行松耦合通信,而不需要显式地注册监听器或调用回调接口。EventBus通过线程模型来控制事件处理函数的执行线程

核心流程就是:EventBus通过使用post方法发出一个Event事件,然后定义一个onEvent()方法,在里面接收事件并进行处理。

二、如何使用呢?

  1. 依赖
implementation("org.greenrobot:eventbus:3.3.1")
  1. 定义事件 (Event)
//事件是pojo对象,没有如何特定的要求
data class MessageEvent(
    val message:String
)
  1. 准备订阅者:也就是接收处理的。(Subscriber)
class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
       
        startService(Intent(this,MyService::class.java))
//        EventBus.getDefault().post(MessageEvent("Hello everyone!"));自己发送,自己收不到的。

    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onMessageEvent(event:MessageEvent){
        //toast被调用时,会在主线程。
        Toast.makeText(this,event.message,Toast.LENGTH_LONG).show()
    }

//    @Subscribe
//    fun handleSomethingElse(event: MessageEvent?) {
//    }
}

(1)@Subscribe(threadMode = ThreadMode.MAIN),用来决定这个方法是在什么线程执行。
订户还需要 在总线上注册 themselves to 和取消注册 。只有当订阅者注册时,他们才会收到事件。在 Android 中,在活动和片段中,您通常应 根据其生命周期进行注册。在大多数情况下,onStart/onStop 工作正常:

    override fun onStart() {
        super.onStart()
        EventBus.getDefault().register(this);
    }

    override fun onStop() {
        EventBus.getDefault().unregister(this);
        super.onStop()

    }
  1. 发布事件(Publisher)
class MyService : Service() {
    override fun onBind(p0: Intent?): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        EventBus.getDefault().post(MessageEvent("Hello everyone!"));
    }
}

Subscribe

  1. 一个Subscribe可以对应多个Event ,也就是说我们可以监听不同的事件,多写几个onMessageEvent方法,
  2. EventBus3.0 开始用Subscribe注解配置事件订阅方法,不再使用方法名 ,有这个注解就会自动找到这个方法。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    // 指定事件订阅方法的线程模式,即在那个线程执行事件订阅方法处理事件,默认为POSTING
    ThreadMode threadMode() default ThreadMode.POSTING;
    // 是否支持粘性事件,默认为false,sticky的作用就是:订阅者可以先不进行注册,如果post事件已经发出,再注册订阅者,同样可以接收到事件,并进行处理。
    boolean sticky() default false;
    // 指定事件订阅方法的优先级,默认为0,如果多个事件订阅方法可以接收相同事件的,则优先级高的先接收到事件
    int priority() default 0;
}

Publisher

  1. EventBus.getDefault()方法是一个单例。
  2. register()方法进行注册:会在当前要注册的类以及其父类中查找订阅事件的方法 ,到时候进行事件调用。unregister为取消注册。
  3. post()方法进行事件发送。

三、五种线程模型

MAIN
● 行为:无论事件在哪个线程发布,事件处理函数都会在主线程(UI线程)中执行。
● 适用场景:适用于需要更新UI的场景,因为UI更新必须在主线程中进行。
● 注意:事件处理的时间不能太长,长了会导致ANR。

BACKGROUND
● 行为:如果事件是在主线程中发布的,那么事件处理函数将在后台线程中执行;如果事件是在后台线程中发布的,则直接在发布线程中执行。
● 适用场景:适用于执行耗时操作且不需要在主线程中执行的场景。
● 注意:在此事件处理函数中禁止进行UI更新操作。

ASYNC
● 行为:无论事件在哪个线程发布,事件处理函数都会在新建的子线程中执行。
● 适用场景:适用于执行耗时操作且不需要关心具体在哪个线程中执行的场景。
● 注意:同样,在此事件处理函数中禁止进行UI更新操作。

POSTING
● 行为:事件在哪个线程发布,就在哪个线程处理。这是EventBus的默认线程模式,避免了线程切换,效率高。
● 适用场景:适用于不需要在主线程执行,且耗时很短的简单任务。
● 注意:在POSTING模式的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR(应用无响应)。

MAIN_ORDERED
● 行为: 确保事件处理函数在主线程(UI线程)中调用,并且这些事件将按照它们被发布的顺序排队等待处理。这意味着,即使事件是在主线程中并发发布的,它们也会按照发布的顺序被处理,而不会打乱。此外,与MAIN模式不同的是,MAIN_ORDERED模式中的事件处理函数会在一个事件队列中等待,直到它们被按顺序处理。
● 适用场景:当需要保证事件处理的顺序时,可以使用此模式。
● 注意:与MAIN模式一样,事件处理的时间也不能太长,否则会导致ANR。

四、Eventbus2和3的区别

  1. 回调方法命名与注解

    EventBus 2:在EventBus 2中,接收事件的方法名需要使用约定的命名规则,例如onEvent、onEventAsync、onEventBackground、onEventMainThread等,通过方法名来判定是否是接收事件的方法以及事件处理的线程模式。
    EventBus 3:在EventBus 3中,接收事件的方法名可以随意命名,但需要通过@Subscribe注解来指定事件处理的方法,并通过注解中的threadMode属性来指定事件处理的线程模式。这种方式提供了更大的灵活性,并且使得代码更加清晰和易于维护。

  2. 线程模型的默认值和多样性

    EventBus 2:线程模型主要通过方法名来区分,如onEventMainThread表示在主线程处理,onEventAsync表示在异步线程处理等。
    EventBus 3:引入了更多的线程模型选项,包括POSTING(默认,与发布事件的线程相同)、MAIN(在主线程处理)、MAIN_ORDERED(在主线程按顺序处理)、BACKGROUND(在后台线程处理)和ASYNC(在异步线程处理)。在未声明threadMode时,EventBus 3默认使用POSTING模式。

  3. 异常处理

    EventBus 3:在EventBus 3中,如果在@Subscribe标注的方法中程序出错,不会程序崩溃,而是由EventBus拦截异常,并打印错误日志。这有助于避免因为单个事件处理失败而导致整个应用崩溃的情况。

  @Subscribe(threadMode = ThreadMode.MAIN)
   fun onMessageEvent(event:MessageEvent){
       //toast被调用时,会在主线程。
       Toast.makeText(this,event.message,Toast.LENGTH_LONG).show()
       println(1/0)
   }

在这里插入图片描述

  1. 性能优化

    EventBus 3:EventBus 3通过利用编译时检索所有注解代码,并生成一个包含所有在运行时要花很大代价才能获取的数据的类,来提升性能。这种新的注解处理方式使得EventBus 3在性能上比EventBus 2有所提升。

eventbus的缺点有哪些?

性能问题

1.反射开销:EventBus在注册时会使用反射来遍历注册对象的方法,以找出带有@Subscribe注解的方法。这种反射操作在注册大量对象或复杂对象时可能会带来较大的性能开销。
2.对象创建:虽然EventBus 3.0开始使用了对象池缓存来减少创建对象的开销,但在高并发场景下,仍然需要关注对象的创建和销毁对性能的影响。

内存泄漏风险

1.问题描述:EventBus要求开发者在适当的时候进行注册和反注册操作。如果忘记在组件销毁时反注册EventBus,那么该组件及其相关的事件订阅者可能会因为EventBus的持有而无法被垃圾回收器回收,从而导致内存泄漏。
2.影响:内存泄漏会严重影响应用的性能和稳定性,甚至可能导致应用崩溃。

相关推荐

  1. kafka--发布-订阅消息系统

    2024-07-22 17:32:03       25 阅读
  2. AndroidEventBus收不到消息的一种情况

    2024-07-22 17:32:03       27 阅读
  3. Springboot整合Redis实现消息发布订阅

    2024-07-22 17:32:03       53 阅读
  4. 【根据消息类型实现订阅发布模型】

    2024-07-22 17:32:03       28 阅读
  5. .Net6 记一次RabbitMq消息订阅/发布优化

    2024-07-22 17:32:03       53 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-22 17:32:03       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-22 17:32:03       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-22 17:32:03       45 阅读
  4. Python语言-面向对象

    2024-07-22 17:32:03       55 阅读

热门阅读

  1. Linux 防火墙配置【iptable,firewalld,ufw】

    2024-07-22 17:32:03       17 阅读
  2. Redisson内置延迟队列RDelayedQueue

    2024-07-22 17:32:03       16 阅读
  3. MYSQL设计和开发规范(简易版)

    2024-07-22 17:32:03       18 阅读
  4. 解决MySQL中LIMIT大偏移量加载慢的问题

    2024-07-22 17:32:03       15 阅读
  5. 【算法】Python中常见的三种优化算法介绍及使用

    2024-07-22 17:32:03       16 阅读
  6. C++版OpenCV_03_图像增强

    2024-07-22 17:32:03       18 阅读
  7. opengaussdb在oepnEuler上安装

    2024-07-22 17:32:03       16 阅读
  8. 求助Python字体下载!

    2024-07-22 17:32:03       13 阅读
  9. 如何在 Nginx 中配置访问日志的格式?

    2024-07-22 17:32:03       16 阅读
  10. 精简的力量:目标检测中的模型压缩技术解析

    2024-07-22 17:32:03       15 阅读