Android中EventBus的简单使用

目录

介绍

EventBus产生的背景

EventBus工作流程图解

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文件中导入依赖库:

java 复制代码
imlementation 'org.greenrobot:eventbus:3.2.0'

2,配置混淆

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

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

java 复制代码
-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()方法。

创建一个事件类

这里我在基础组件下创建

java 复制代码
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

java 复制代码
@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)来发起事件

java 复制代码
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。 完整的写法如下**:**

java 复制代码
@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的代码

java 复制代码
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事件和事件接收处理,处于同一个线程环境的时候,才有意义

修改代码

java 复制代码
@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博客

相关推荐
openinstall全渠道统计3 小时前
免填邀请码工具:赋能六大核心场景,重构App增长新模型
android·ios·harmonyos
双鱼大猫3 小时前
一句话说透Android里面的ServiceManager的注册服务
android
双鱼大猫3 小时前
一句话说透Android里面的查找服务
android
双鱼大猫4 小时前
一句话说透Android里面的SystemServer进程的作用
android
双鱼大猫4 小时前
一句话说透Android里面的View的绘制流程和实现原理
android
双鱼大猫4 小时前
一句话说透Android里面的Window的内部机制
android
双鱼大猫5 小时前
一句话说透Android里面的为什么要设计Window?
android
双鱼大猫5 小时前
一句话说透Android里面的主线程创建时机,frameworks层面分析
android
苏金标5 小时前
android 快速定位当前页面
android
雾里看山9 小时前
【MySQL】内置函数
android·数据库·mysql