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

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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/260923.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SE-Net:Squeeze-and-Excitation Networks(CVPR2018)

文章目录 AbstractIntroduction表征的重要性以前的方向本文提出 Related WorkDeeper ArchitectureAlgorithmic Architecture SearchAttention and gating mechanisms Squeeze-and-Excitation BlocksSqueeze: Global Information EmbeddingExcitation: Adaptive RecalibrationIn…

ssm基于vue的厨房管理系统论文

摘 要 使用旧方法对厨房管理信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在厨房管理信息的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。 这次开发的厨房管理系统管…

【Python-批量修改视频分辨率】

Python-批量修改视频分辨率 1 使用Python修改视频分辨率2 常见的视频编码格式2.1 等效的编码格式表示方式2.2 常见的编码格式 1 使用Python修改视频分辨率 首先拷贝视频文件并修改后缀&#xff0c;然后修改图片的分辨率&#xff0c;实现视频批量修改和转换。 import os impor…

自定义注解实现 后台系统-记录日志功能

文章目录 1 记录日志1.1 记录日志的意义1.2 日志数据表结构1.3 记录日志思想1.4 切面类环境搭建1.4.1 日志模块创建1.4.2 自定义Log注解1.4.3 OperatorType1.4.4 LogAspect1.4.5 EnableLogAspect1.4.6 测试日志切面类 1.5 保存日志数据1.5.1 SysOperLog1.5.2 LogAspect1.5.3 As…

【教程】cocos2dx资源加密混淆方案详解

1,加密,采用blowfish或其他 2,自定是32个字符的混淆code 3,对文件做blowfish加密,入口文件加密前将混淆code按约定格式(自定义的文件头或文件尾部)写入到文件 4,遍历资源目录,对每个文件做md5混淆,混淆原始串“相对路径”“文件名”混淆code, 文件改名并且移动到资源目录根…

C# try-catch异常处理的用法

try-catch 是一种在编程语言中用于捕获和处理异常的结构。它的作用是在可能引发异常的代码块中进行异常处理&#xff0c;以避免程序崩溃或产生不可预料的结果。 当在 try 块中的代码执行时&#xff0c;如果发生了异常&#xff0c;程序会立即跳转到对应的 catch 块。catch…

http客户端Feign

http客户端Feign 文章目录 http客户端Feign定义和使用Feign客户端自定义Feign的配置Feign的性能优化feign的最佳实践 定义和使用Feign客户端 <!-- feign客户端依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>s…

为什么C语言没有被C++所取代呢?

今日话题&#xff0c;为什么C语言没有被C所取代呢&#xff1f;虽然C是一个功能更强大的语言&#xff0c;但C语言在嵌入式领域仍然广泛使用&#xff0c;因为它更轻量级、更具可移植性&#xff0c;并且更适合在资源受限的环境中工作。这就是为什么C语言没有被C所取代的原因。如果…

玩转 Scrapy 框架 (一):Scrapy 框架介绍及使用入门

目录 一、Scrapy 框架介绍二、Scrapy 入门 一、Scrapy 框架介绍 简介&#xff1a; Scrapy 是一个基于 Python 开发的爬虫框架&#xff0c;可以说它是当前 Python 爬虫生态中最流行的爬虫框架&#xff0c;该框架提供了非常多爬虫的相关组件&#xff0c;架构清晰&#xff0c;可扩…

高速视频采集卡设计方案:620-基于PCIe的高速视频采集卡

一、产品概述 基于PCIe的高速视频采集卡&#xff0c;通过PCIe3.0X8传输到存储计算服务器&#xff0c;实现信号的分析、存储。 北京太速科技 产品固化FPGA逻辑&#xff0c;适配视频连续采集&#xff0c;缓存容量2GB&#xff0c;开源的PCIe QT客户端软件&#xff0c…

常用网络接口自动化测试框架

(一&#xff09;GUI界面测试工具&#xff1a;jmeter 1、添加线程组 2、添加http请求 3、为线程组添加察看结果树 4、写入接口参数并运行 5、在查看结果树窗口查看结果 6、多组数据可增加CSVDataSetConfig(添加.csv格式的文件&#xff0c;并在参数值里以${x}格式写入) 此时变量…

第五讲观测值中与卫星、接收机有关的误差 第六讲观测值中与信号传播路径有关的误差以及电离层、对流层相关模型 | GNSS(RTK)课程学习笔记day3

说明&#xff1a;以下笔记来自计算机视觉life吴桐老师课程&#xff1a;从零掌握GNSS、RTK定位[链接]&#xff0c;从零掌握RTKLIB[链接]。非原创&#xff01;且笔记仅供自身与大家学习使用&#xff0c;无利益目的。 第五讲 观测值中与卫星、接收机有关的误差 卫星轨道误差 由卫…

如何有效压缩图片大小?保持质量的同时减小文件大小

图片体积过大&#xff0c;不仅仅会导致我们电脑或者手机内存不足&#xff0c;在一些网络平台上传的时候&#xff0c;也会因为限制上传失败&#xff0c;为了有效减少文件所占用的存储空间和上传&#xff0c;我们可以先利用图片压缩功能去把图片缩小kb&#xff0c;那么具体是怎么…

Python Pandas 多重索引DataFrame数据(第19讲)

Python Pandas 多重索引DataFrame数据(第19讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

【powershell】Windows环境powershell 运维之历史文件压缩清理

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&am…

Find My资讯|苹果Find My大升级:可添加物品数量翻倍,从16个飙升至32个!

苹果Find My是Find My iPhone&#xff08;查找我的iPhone&#xff09;和Find My Friends&#xff08;查找朋友&#xff09;的结合体&#xff0c;新系统中苹果为了追求简洁&#xff0c;于是把这两个应用整合到一块了。Find My作用于iOS13、iPadOS&#xff08;苹果为iPad定制的新…

笨爸爸工房携手洛阳科学技术馆,开启全新手工课程!

笨爸爸工房与洛阳科学技术馆达成合作&#xff0c;每周六上午9点50分在洛阳科学技术馆开设全新的手工课程。通过丰富多彩的手工课程&#xff0c;让孩子在动手实践中感受传统木艺的乐趣&#xff0c;了解中国传统文化的内涵。笨爸爸工房以木工为媒介&#xff0c;希望通过提升父亲参…

LeetCode 739每日温度 496 下一个更大元素 | 代码随想录25期训练营day58

单调栈1 LeetCode 739 每日温度 2023.12.21 题目链接代码随想录讲解[链接] vector<int> dailyTemperatures(vector<int>& temperatures) {//暴力求解&#xff0c;但会超时/*vector<int> answer(temperatures.size(), 0);for (int i 0; i < tempe…

BWS2000倾角传感器c++测试代码【2】

问题一&#xff1a;串口频率的初始化 由于本次项目之中使用的线长为40米的倾角传感器&#xff0c;需要对于其频率输出存在要求&#xff0c;如何测试其频率如下所示&#xff1a; 如上所示相应的软件&#xff0c;软件中存在一句如果设置后不保存&#xff0c;则存在传感器断电后设…

开源堡垒机JumpServer结合内网穿透实现远程访问

开源堡垒机JumpServer结合内网穿透实现远程访问 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机&#xff0c;是符合 …