Android中EventBus的简单使用

发布时间:2023年12月21日

?

目录

?

介绍

EventBus产生的背景

EventBus工作流程图解

EventBus的优势

EventBus缺点

EventBus 的一些关键概念和用法:

使用 EventBus 的基本流程:

EventBus环境配置

EventBus的五种线程模式

EventBus的使用

EventBus事件三部曲

创建一个事件类

注册EventBus

? ? 创建订阅者发起通知

效果

MainActivity

?编辑

?在FirstActivity中发送消息,MainActivity也能接收到

Subscribe注解介绍

黏性sticky

效果

?优先级priority

效果


注:本文基于组件化项目举例并使用

Android组件化基础(一)——概述与基本配置-CSDN博客

Android组件化基础(二)——组件间的通信-CSDN博客

介绍

? ? ? ? Android系统内置的事件通讯存在缺点:
????????Android系统中的事件通信则是 handler (消息机制) 和 BroadCastReceiver (广播机制), 通过它们可以实现组件之间的事件通讯。缺点在于,代码量多、组件之易产生藕合引用。

EventBus产生的背景

? ? ? ? 当我们进行项目开发的时候,经常会遇到组件与组件之间、组件与后台线程之间的通信, 比如:子线程中执行数据请求,数据请求成功后,通过 Handler 或者 BroadCast 来通知UI更新。 两个Fragment之间可以通过Listener进行通信,但是问题来了,当程序越来越大时,就会要写很多的代码, 而且导致代码严重的耦合问题。为此 ,EventBus 应运而生。

EventBus工作流程图解

EventBus的官方文档:EventBus: Events for Android - Open Source by greenrobot

? ? ? ? Publisher使用post发出一个Event事件,Subscriber在onEvent()函数中接收事件。

????????EventBus 是一个开源的 Android 事件发布/订阅框架,用于简化组件或者线程之间的通信。它采用了观察者设计模式,允许不同组件之间通过发布和订阅事件来实现解耦和松散耦合,从而提高代码的可维护性和可扩展性。

EventBus的优势

1,简化组件之间的通讯方式
2,对通信双方进行解藕
3,使用ThreadMode灵活切换工作线程
4,速度快、性能好
5,库比较小,不占内存

EventBus缺点

1、使用的时候有定义很多event类
2、event在注册的时候会调用反射去遍历注册对象的方法在其中找出带有@subscriber标签的方法,性能不高。
3、需要自己注册和反注册,如果忘了反注册就会导致内存泄漏

EventBus 的一些关键概念和用法:

  1. 事件(Event):在 EventBus 中,事件是一个普通的 Java 对象,用于在不同组件之间传递信息。

  2. 订阅者(Subscriber):订阅者是对事件感兴趣并通过订阅(注册)来接收事件的组件或类。订阅者需要定义一个或多个用于处理事件的方法。

  3. 发布者(Publisher):发布者是负责发布事件的组件或类。它们通过事件的类型来标识事件,并将事件发送给所有订阅了该类型事件的订阅者。

  4. 订阅(Subscribe):订阅是指让订阅者注册到 EventBus 中,以便接收特定类型的事件。通过注解或代码方式将订阅者注册到 EventBus。

  5. 事件处理方法:订阅者需要定义用于处理特定类型事件的方法。这些方法使用特定的注解来标记,例如?@Subscribe。当事件被发布时,EventBus 将自动调用对应订阅者的处理方法。

  6. 线程模式(Thread Mode):EventBus 支持不同的线程模式,用于控制事件处理方法在哪个线程被调用。例如,ThreadMode.MAIN?表示事件处理方法在主线程中执行,ThreadMode.BACKGROUND?表示在后台线程中执行。

使用 EventBus 的基本流程:

  1. 定义事件类:创建一个用于传递信息的事件类。

  2. 注册订阅者:在订阅者中注册到 EventBus,标识对哪些事件感兴趣,并定义事件处理方法。

  3. 发布事件:在发布者中创建事件对象并使用 EventBus 发布事件。

  4. 处理事件:EventBus 将自动将事件分发给订阅者,并调用对应的事件处理方法。

????????EventBus 提供了简洁的 API 和灵活的配置选项,使得在 Android 应用程序中实现组件间的事件通信变得更加简单和高效。

EventBus环境配置

1,依赖导入

????????在app module的builde.gradle文件中导入依赖库:

imlementation ‘org.greenrobot:eventbus:3.2.0’

2,配置混淆

????????必须配置,否则会出现,debug环境正常,release环境接收不到事件的问题

????????在使用的组件或者包下的proguard-rules.pro文件内修改

-keepattributes *Annotation*
-keepclassmembers class * {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}

EventBus的五种线程模式

? ? ? ? 在事件订阅者使用@Subscribe注解标记回调函数时,需要指定线程模式,未指定默认为POSTING。

????????ThreadMode.POSTING:默认线程模式。订阅者方法将会在发布事件的同一线程中被调用。事件的传递是同步的,一旦发布事件,所有该模式的订阅者方法都将被调用。这种线程模式以为着最少的性能开销,因为他避免了线程切换。因此对于耗时短并且不需要主线程的简单任务,推荐使用这种模式。使用这种模式的事件处理应该快速返回,因为有可能事件是在主线程中发布的。

????????ThreadMode.MAIN:订阅者方法将会在主线程中调用。如果发布事件的线程也是主线程,那么和指定为ThreadMode.POSTING一样,不需要切换线程运行。使用这种模式的事件处理必须快速返回,否则会阻塞主线程。

????????ThreadMode.MIAN_ORDERED:订阅者方法会在主线程中被调用。发布者发布的事件会进入队列,依照先后顺序依次发送给订阅者。所以叫Ordered。

????????例如:如果在MAIN线程模式中的事件处理(称为第一事件)中去发布另外一个事件(称为第二事件),第二事件的订阅者的线程模式也是MAIN,那么第二事件会在第一事件处理结束前就开始处理。但是如果第二事件的订阅者的线程模式是MAIN_ORDERED,那么在第一事件结束的稍后的事件就会开始处理第二事件。

????????同样,使用此模式的事件处理必须快速返回,以免阻塞主线程。

????????ThreadMode.BACKGROUND:订阅者方法将在后台线程中被调用。如果发布事件的线程不是主线程,则将直接在发布线程中调用事件处理方法;如果是主线程,那么EventBus会创建一个单独的后台线程,该线程将按照顺序传递所有事件。使用此这种模式的事件处理应该尽量快速返回,避免阻塞后台线程。使用这种线程模式不会在主线程中处理事件。

????????ThreadMode.ASYNC:订阅者方法将会在一个单独的线程中被调用。这个线程始终独立于发布线程和主线程。如果事件处理方法的执行可能需要一些时间,例如网络访问,则应该使用此模式。

EventBus的使用

EventBus事件三部曲

????????Subscriber、Event、Publisher。
????????Subscriber ? —— EventBus的register方法,会接收到一个Object对象。
????????Event ? ? ? ? ? —— EventBus的post()方法中传入的事件类型 (可以是任意类型)。
????????Publisher ? ? —— EventBus的post()方法。

创建一个事件类

这里我在基础组件下创建

package com.example.module.libbase;

public class Msg {
    public int id;
    public String msg;

    public Msg(int id, String msg) {

        this.id = id;
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "id=" + id + ", msg='" + msg;
    }
}

注册EventBus

在需要订阅事件的模块中,注册EventBus?

@Route(path = "/app/MainActivity")
public class MainActivity extends AppCompatActivity {

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
    }
    @Override
    protected void onStart() {
        super.onStart();
        if (!EventBus.getDefault().isRegistered(this))
            EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }
    //接收事件
    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true,priority = 1)
    public void ReceiveMessage1(Msg msg){
        text1.setText(msg.toString());
    }
    //接收事件
    @Subscribe(threadMode = ThreadMode.POSTING,sticky = true,priority = 1)
    public void ReceiveMessage2(Msg msg){
        text2.setText(msg.toString());
    }
    //接收事件
    @Subscribe(threadMode = ThreadMode.BACKGROUND,sticky = true,priority = 1)
    public void ReceiveMessage3(Msg msg){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                text3.setText(msg.toString());
            }
        });
    }
    //接收事件
    @Subscribe(threadMode = ThreadMode.ASYNC,sticky = true,priority = 1)
    public void ReceiveMessage4(Msg msg){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                text4.setText(msg.toString());
            }
        });
    }
    //接收事件
    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED,sticky = true,priority = 1)
    public void ReceiveMessage5(Msg msg){
        text5.setText(msg.toString());
    }
}

? ? 创建订阅者发起通知

????????使用eventbus.post(eventMessage) 或者 eventbus.postSticky(eventMessage)来发起事件

button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                EventBus.getDefault().post(new Msg(111,"This is MainActivity"));
            }
        });

效果

MainActivity

发送消息111

?在FirstActivity中发送消息,MainActivity也能接收到

发送消息333

Subscribe注解介绍

????????Subscribe是EventBus自定义的注解,共有三个参数(可选):threadMode、boolean sticky、int priority。?完整的写法如下

@Subscribe(threadMode = ThreadMode.MAIN,sticky = true,priority = 1)
public void onReceiveMsg(EventMessage message) {
    Log.e(TAG, "onReceiveMsg: " + message.toString());
}

?threadMode在之前已经介绍过了,接下来我们介绍 黏性sticky 和 优先级priority。

黏性sticky

????????sticky是一个boolean类型,默认值为false,默认不开启黏性sticky特性,那么什么是sticky特性呢?
????????上面的例子都是对订阅者 (接收事件) 先进行注册,然后在进行post事件。那么sticky的作用就是:订阅者可以先不进行注册,如果post事件已经发出,再注册订阅者,同样可以接收到事件,并进行处理。
????????其实就是在sticky场景下,EventBus对事件进行了保存而已。

修改MainActivity的代码

button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                EventBus.getDefault().postSticky(new Msg(111,"This is MainActivity"));
            }
        });

可以注意到post被改成了postSticky。

效果

没改成postSticky之前,MainActivity发送消息FirstActivity无法收到,因为没有注册EventBus

?修改后

?

?优先级priority

????????priority优先级,是一个int类型,默认值为0。值越大,优先级越高,越优先接收到事件。

值得注意的是,只有在post事件和事件接收处理,处于同一个线程环境的时候,才有意义

?????????修改代码

@Subscribe(threadMode = ThreadMode.MAIN,sticky = true,priority = 10)
    public void ReceiveMessage1(Msg msg){
        text1.setText(msg.toString());
    }
    @Subscribe(threadMode = ThreadMode.POSTING,sticky = true,priority = 8)
    public void ReceiveMessage2(Msg msg){
        text2.setText(msg.toString());
        EventBus.getDefault().cancelEventDelivery(msg);//取消传递消息
    }
    @Subscribe(threadMode = ThreadMode.BACKGROUND,sticky = true,priority = 6)
    public void ReceiveMessage3(Msg msg){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                text3.setText(msg.toString());
            }
        });
    }
    @Subscribe(threadMode = ThreadMode.ASYNC,sticky = true,priority = 4)
    public void ReceiveMessage4(Msg msg){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                text4.setText(msg.toString());
            }
        });
    }
    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED,sticky = true,priority = 1)
    public void ReceiveMessage5(Msg msg){
        text5.setText(msg.toString());
    }

?????????我在优先级为8的订阅者接收消息后添加了该代码:EventBus.getDefault().cancelEventDelivery(msg);取消了信息传递。

效果

可以看到,第二个TextView之后都没变化

?????????另外,cancelEventDelivery?方法只在事件处理方法内部的事件发布线程上调用,即取消消息传递和发送消息的得是同一个线程。如果cancelEventDelivery?方法放在优先级为6的订阅者里执行,会报错。

?

上一篇:Android组件化基础(二)——组件间的通信-CSDN博客

本文参考:EventBus详解 (详解 + 原理)-CSDN博客

EventBus的基本使用-CSDN博客

文章来源:https://blog.csdn.net/Sean_Word/article/details/135119628
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。