当前位置: 首页 > news >正文

EventBus 开源库学习(一)

一、概念

EventBus是一款在 Android 开发中使用的发布-订阅事件总线框架,基于观察者模式,将事件的接收者和发送者解耦,简化了组件之间的通信,使用简单、效率高、体积小。

一句话:用于Android组件间通信的。

二、原理

image.png

三、简单使用

  • 在app module的builde.gradle文件中导入依赖库:
implementation 'org.greenrobot:eventbus:3.3.1'
  • 配置混淆
-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);
}

1、订阅者EventBusService后台注册,前台EventBusActivity 发送的数据。注册以后一定要记得解注册,否则会内存泄漏。onMsgEventReceived是接收消息的方法,该方法定义需要注意:

  • 该方法有且仅有一个参数;
  • 必须用public修饰,不能使用static或者abstract
  • 需要添加@Subscribe()注解;
public class EventBusService extends Service {private static final String TAG = "Test_EventBusService";@Overridepublic void onCreate() {super.onCreate();//注册数据监听EventBus.getDefault().register(this);}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Subscribepublic void onMsgEventReceived(String msg) {Log.i(TAG, "String msg: " + msg);}@Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 1)public void onMsgEventReceived(MsgEvent event) {Log.i(TAG, "MsgEvent msg: " + event.getMsg());}@Overridepublic void onDestroy() {super.onDestroy();//解注册数据监听EventBus.getDefault().unregister(this);}
}

2、前台Activity在按钮点击的时候发送信息到后台Service。

public class EventBusActivity extends AppCompatActivity {private static final String TAG = "Test_EventBusActivity";@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_event_bus);Button msg1Btn = findViewById(R.id.btn1);Button msg2Btn = findViewById(R.id.btn2);msg1Btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送数据给监听者EventBus.getDefault().post("msg1 - coming!!!");}});msg2Btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送数据给监听者MsgEvent event = new MsgEvent("msg2 - coming!!!");EventBus.getDefault().post(event);}});}@Overrideprotected void onDestroy() {super.onDestroy();}
}

3、MsgEvent数据类型。

public class MsgEvent {private String msg;public MsgEvent(String msg) {this.msg = msg;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}@Overridepublic String toString() {return "MsgEvent{" +"msg='" + msg + '\'' +'}';}
}

4、运行结果
运行结果.png

四、Subscribe注解

Subscribe是EventBus自定义的注解,共有三个参数(可选):ThreadModeboolean stickyint priority

@Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 1)
public void onMsgEventReceived(MsgEvent event) {Toast.makeText(this, event.getMsg(), Toast.LENGTH_LONG).show();
}

1、ThreadMode取值:

  • ThreadMode.POSTING:默认的线程模式,在哪个线程发送事件就在对应线程处理事件。避免了线程切换,效率高。

代码测试:

#EventBusActivity 
msg1Btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送数据给监听者new Thread(new Runnable() {@Overridepublic void run() {Log.i(TAG, "post thread: " + Thread.currentThread().getName());EventBus.getDefault().post("msg1 - coming!!!");}}).start();}});#EventBusService
@Subscribe
public void onMsgEventReceived(String msg) {Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());Log.i(TAG, "String msg: " + msg);
}

post的动作放到子线程中,结果如下,在哪个线程发送,就会在哪个线程执行:
Thread.POSTING.png

  • ThreadMode.MAIN:如在主线程(UI线程)发送事件,则直接在主线程处理事件;如果在子线程发送事件,则先将事件入队列,然后通过Handler切换到主线程,依次处理事件。

该模式下,在主线程(UI线程)发送事件,则直接在主线程处理事件,如果处理方法中有耗时操作就会堵塞进程。

代码测试1:

#EventBusActivity 
msg1Btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送数据给监听者new Thread(new Runnable() {@Overridepublic void run() {Log.i(TAG, "post thread: " + Thread.currentThread().getName());EventBus.getDefault().post("msg1 - coming!!!");}}).start();}});#EventBusService
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMsgEventReceived(String msg) {Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());Log.i(TAG, "String msg: " + msg);
}

发送post代码放到子线程中,处理事件代码加上ThreadMode.MAIN注解参数,结果如下,可以用在子线程处理耗时操作,然后返回值需要切回到主线程刷新UI的场景:
Thread.MAIN.png
代码测试2:

#EventBusActivity 
msg1Btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送数据给监听者Log.i(TAG, "post thread: " + Thread.currentThread().getName());EventBus.getDefault().post("msg1 - coming!!!");Log.i(TAG, "post thread: " + Thread.currentThread().getName());EventBus.getDefault().post("msg1-1 - coming!!!");}});#EventBusService
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMsgEventReceived(String msg) {Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());Log.i(TAG, "String msg: " + msg);try {Thread.sleep(2 * 1000);} catch (InterruptedException e) {e.printStackTrace();}
}

发送post放在主线程并连续发送两次,接收事件的函数加上耗时操作,运行结果如下,两次post打印就相隔2s,第二次post需要等第一次事件接收处理完以后才能发出,所以主线程会阻塞:
Thread.MAIN_阻塞.png

同样修改下发出post的代码放到子线程后没有这个问题,结果如下:
Thread.MAIN_子线程非阻塞.png

  • ThreadMode.MAIN_ORDERED:无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
    代码测试:
#EventBusActivity 
msg1Btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送数据给监听者Log.i(TAG, "post thread: " + Thread.currentThread().getName());EventBus.getDefault().post("msg1 - coming!!!");Log.i(TAG, "post thread: " + Thread.currentThread().getName());EventBus.getDefault().post("msg1-1 - coming!!!");}});#EventBusService
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMsgEventReceived(String msg) {Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());Log.i(TAG, "String msg: " + msg);try {Thread.sleep(2 * 1000);} catch (InterruptedException e) {e.printStackTrace();}
}

代码和ThreadMode.MAIN测试2一样,只是将threadMode改为了MAIN_ORDERED,运行结果如下,两次post可以连续发出:
MAIN_ORDERED.png

  • ThreadMode.BACKGROUND:如果在主线程发送事件,则先将事件入队列,然后通过线程池依次处理事件;如果在子线程发送事件,则直接在发送事件的子线程处理事件。
    代码测试1:
msg1Btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送数据给监听者Log.i(TAG, "post thread: " + Thread.currentThread().getName());EventBus.getDefault().post("msg1 - coming!!!");}});#EventBusService
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMsgEventReceived(String msg) {Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());Log.i(TAG, "String msg: " + msg);
}

运行结果如下,主线程发送事件,线程池依次处理事件:
ThreadMode.BACKGROUND.png

代码测试2:

msg1Btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送数据给监听者new Thread(new Runnable() {@Overridepublic void run() {Log.i(TAG, "post thread: " + Thread.currentThread().getName());EventBus.getDefault().post("msg1 - coming!!!");}}).start();}});#EventBusService
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMsgEventReceived(String msg) {Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());Log.i(TAG, "String msg: " + msg);
}

运行结果,子线程发送事件,则直接在发送事件的子线程处理事件:
ThreadMode.BACKGROUND_子线程.png

  • ThreadMode.ASYNC:无论在那个线程发送事件,都将事件入队列,然后通过线程池处理。
    代码测试1:
msg1Btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送数据给监听者Log.i(TAG, "post thread: " + Thread.currentThread().getName());EventBus.getDefault().post("msg1 - coming!!!");}});#EventBusService
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMsgEventReceived(String msg) {Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());Log.i(TAG, "String msg: " + msg);
}

运行结果,主线程发送,线程池处理:
ThreadMode.ASYNC_主线程.png
代码测试2:

msg1Btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//发送数据给监听者new Thread(new Runnable() {@Overridepublic void run() {Log.i(TAG, "post thread: " + Thread.currentThread().getName());EventBus.getDefault().post("msg1 - coming!!!");}}).start();}});#EventBusService
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMsgEventReceived(String msg) {Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());Log.i(TAG, "String msg: " + msg);
}

运行结果,子线程发送,线程池处理:
ThreadMode.ASYNC_子线程.png

2、sticky:

sticky是否为粘性监听,boolean类型,默认值为false。正常我们都是先订阅,才能接收到发出的事件,sticky的作用就是订阅者可以先不进行注册,事件先发出,再注册订阅者,同样可以接收到事件,并进行处理。

3、priority:

priority是优先级,int类型,默认值为0。值越大,优先级越高,越优先接收到事件。值得注意的是,只有在post事件和事件接收处理,处于同一个线程环境的时候,才有意义。

参考文章
EventBus详解 (详解 + 原理)

相关文章:

EventBus 开源库学习(一)

一、概念 EventBus是一款在 Android 开发中使用的发布-订阅事件总线框架&#xff0c;基于观察者模式&#xff0c;将事件的接收者和发送者解耦&#xff0c;简化了组件之间的通信&#xff0c;使用简单、效率高、体积小。 一句话&#xff1a;用于Android组件间通信的。 二、原理…...

车载以太网SOME/IP的个人总结

如何实现CAN-SOME/IP通信路由测试 (qq.com) AutoSAR SOMEIP与SOC vsomeip通讯 (qq.com) 利用commonAPI和vSomeip对数据进行序列化 (qq.com) Vector - CANoe - VCDL与SomeIP (qq.com) 使用Wireshark 查看SOMEIP的方法 (qq.com) 基于AutoSAR的车载以太网测试 - SOMEIP之ECU做…...

vue2.29-Vue3跟vue2的区别

1、vue3介绍 更新&#xff08;和重写&#xff09;Vue的主要版本时&#xff0c;主要考虑两点因素&#xff1a;首先是新的JavaScript语言特性在主流浏览器中的受支持水平&#xff1b;其次是当前代码库中随时间推移而逐渐暴露出来的一些设计和架构问题。 相较于vue2&#xff0c;vu…...

【深度学习】分类和分割常见损失函数

分类 分类是一种监督机器学习任务&#xff0c;其中训练模型来预测给定输入数据点的类或类别。分类旨在学习从输入特征到特定类或类别的映射。 有不同的分类任务&#xff0c;例如二元分类、多类分类和多标签分类。 二元分类是一项训练模型来预测两个类别之一的任务&#xff0c…...

Redhat Linux 安装MySQL安装手册

Redhat安装MySQL安装手册 1 下载2 上传服务器、解压并安装3 安装安装过程1&#xff1a;MySQL-shared-5.6.51-1.el7.x86_64.rpm安装过程2&#xff1a;MySQL-shared-compat-5.6.51-1.el7.x86_64.rpm安装过程3&#xff1a;MySQL-server-5.6.51-1.el7.x86_64.rpm安装过程4&#xff…...

题目:2303.计算应缴税款总额

​​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;2303. 计算应缴税款总额 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 按要求计算即可。注意最多产生 n1 个不同区间内的税款即可。 解题代码&#xff1a; class Solution {public doub…...

Kotlin 1.9.0 发布:带来多项新特性,改进 Multiplatform/Native 支持

新特性 Kotlin 的最新版本引入了许多新的语言特性&#xff0c;包括用于开放范围的…<操作符、扩展正则表达式等。此外&#xff0c;它还改进了 Kotlin Multiplatform 和 Kotlin/Native 支持。 Kotlin 1.9 稳定了与枚举类关联的 entries 属性&#xff0c;它会返回所定义的枚…...

接口测试——认知(一)

目录 引言 环境准备 1. 为什么要进行接口测试 2. 什么是接口 3. 接口测试与功能测试的区别 引言 为什么要做接口自动化测试&#xff1f; 在当前互联网产品迭代频繁的背景下&#xff0c;回归测试的时间越来越少&#xff0c;很难在每个迭代都对所有功能做完整回归。 但接…...

剑指 Offer 10- I. 斐波那契数列

写一个函数&#xff0c;输入 n &#xff0c;求斐波那契&#xff08;Fibonacci&#xff09;数列的第 n 项&#xff08;即 F(N)&#xff09;。斐波那契数列的定义如下&#xff1a; F(0) 0, F(1) 1 F(N) F(N - 1) F(N - 2), 其中 N > 1. 斐波那契数列由 0 和 1 开始&am…...

洪水填充算法详解

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;算法、前端、JavaScript、HTML、洪水填充算法☀️每日 一言&#xff1a;不以物喜&#xff0c;不以己悲 一、前言 当象一个容器中注水时&#xff0c;无论容器的结构如何复杂&#xff0c;注入的水…...

ubuntu18.04安装docker及docker基本命令的使用

官网安装步骤&#xff1a;https://docs.docker.com/desktop/install/ubuntu/ docker快速入门教程 Ubuntu-Docker安装和使用 docker官网 docker-hub仓库 1、常用指令 &#xff08;1&#xff09;镜像操作 # ############################# 以nginx为例 docker images docker p…...

DataWhale 机器学习夏令营第二期——AI量化模型预测挑战赛 学习记录

DataWhale 机器学习夏令营第二期 学习记录一 (2023.08.06)1. 问题建模1.1 赛事数据数据集情况数据中缺失值类别和数值特征的基本分布 1.2 评价指标中间价的计算方式价格移动方向说明 1.3 线下验证 DataWhale 机器学习夏令营第二期 ——AI量化模型预测挑战赛 已跑通baseline&…...

简单认识ELK日志分析系统

一. ELK日志分析系统概述 1.ELK 简介 ELK平台是一套完整的日志集中处理解决方案&#xff0c;将 ElasticSearch、Logstash 和 Kiabana 三个开源工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 好处&#xff1a; &#xff08;1&#xff09;提高安全…...

【算法笔记】深度优先遍历-解决排列组合问题-

深度优先遍历-解决排列组合问题 问题1&#xff1a; 假设袋子里有编号为1,2,…,m这m个球。现在每次从袋子中取一个球记下编号&#xff0c;放回袋中再取&#xff0c;取n次作为一组&#xff0c;枚举所有可能的情况。 分析&#xff1a; 每一次取都有m种可能的情况&#xff0c;因此…...

【雕爷学编程】Arduino动手做(184)---快餐盒盖,极低成本搭建机器人实验平台2

吃完快餐粥&#xff0c;除了粥的味道不错之外&#xff0c;我对个快餐盒的圆盖子产生了兴趣&#xff0c;能否做个极低成本的简易机器人呢&#xff1f;也许只需要二十元左右 知识点&#xff1a;轮子&#xff08;wheel&#xff09; 中国词语。是用不同材料制成的圆形滚动物体。简…...

应急响应-勒索病毒的处理思路

0x00 关于勒索病毒的描述 勒索病毒入侵方式&#xff1a;服务弱口令&#xff0c;未授权&#xff0c;邮件钓鱼&#xff0c;程序木马植入&#xff0c;系统漏洞等 勒索病毒的危害&#xff1a;主机文件被加密&#xff0c;且几乎难以解密&#xff0c;对主机上的文件信息以及重要资产…...

ChatGPT是否能够处理多模态数据和多模态对话?

ChatGPT有潜力处理多模态数据和多模态对话&#xff0c;这将进一步扩展其在各种应用领域中的实用性。多模态数据是指包含多种不同类型的信息&#xff0c;例如文本、图像、音频和视频等。多模态对话是指涉及多种媒体形式的对话交流&#xff0c;例如同时包含文本和图像的对话。 *…...

AcWing1171. 距离(lcatarjan)

输入样例1&#xff1a; 2 2 1 2 100 1 2 2 1输出样例1&#xff1a; 100 100输入样例2&#xff1a; 3 2 1 2 10 3 1 15 1 2 3 2输出样例2&#xff1a; 10 25 #include<bits/stdc.h> using namespace std; typedef long long ll; const int N2e55; int n,m,x,y,k,r…...

JVM-运行时数据区

目录 什么是运行时数据区&#xff1f; 方法区 堆 程序计数器 虚拟机栈 局部变量表 操作数栈 动态连接 运行时常量池 方法返回地址 附加信息 本地方法栈 总结&#xff1a; 什么是运行时数据区&#xff1f; Java虚拟机在执行Java程序时&#xff0c;将它管…...

RedisTemplate中boundHashOps的使用

1、往指定key中存储 键值 redisTemplate.boundHashOps("demo").put("1",1); 2、根据指定key中得键取出值 System.out.println(redisTemplate.boundHashOps("demo").get("1")); 3、根据指定key中得键删除 redisTemplate.boundHash…...

计算机网络-性能指标

计算机网络-性能指标 文章目录 计算机网络-性能指标简介速率比特速率 带宽吞吐量时延时延计算 时延带宽积往返时间网络利用率丢包率总结 简介 性能指标可以从不同的方面来度量计算机网络的性能 常用的计算机网络的性能指标有以下8个 速率带宽吞吐量时延时延带宽积往返时间利…...

排序第一课【插入排序】直接插入排序 与 希尔排序

目录 1. 排序的概念&#xff1a; 2.插入排序基本思想 3.直接插入排序 4.希尔排序 1. 排序的概念&#xff1a; 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xf…...

云计算——ACA学习 云计算概述

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 目录 写在前面 上章回顾 本章简介 本章目标 一.云计算产生背景 1.信息时代的重点变革…...

如何为网站进行全面的整站翻译?

要翻译整个网站&#xff0c;可以按照以下步骤进行&#xff1a; 确定翻译需求&#xff1a;确定你需要将整个网站翻译成哪种语言。这可以根据你的目标受众和市场进行决定。 寻找翻译资源&#xff1a;你可以选择以下几种方式来进行网站翻译&#xff1a; a. 人工翻译&#xff1a;雇…...

项目部署(前后端分离)

1、前端项目 &#xff08;打包成dist文件,放到nginx的html目录下面&#xff09;&#xff0c;然后配置nginx 2、后端项目部署 使用之前的shell脚本&#xff08;然后赋予用户权限&#xff09;&#xff0c;最后运行脚本 查看进程...

增强型Web安全网关在银行的应用

销售&#xff0c;绝不是降低身份去取悦客户&#xff0c;而是像朋友一样给予合理的建议。你刚好需要&#xff0c;我刚好专业&#xff01;仅此而已&#xff01; 乔.吉拉德 健康的安全体系&#xff0c;还可以更完善 浙江某商业银行股份有限公司是一家成立多年的商业银行&#xf…...

Oracle-ORA-00600:[ktspffbmb:objdchk_kcbnew_3]

问题背景: 应用执行存储过程报错ORA-00600: 内部错误代码, 参数: [ktspffbmb:objdchk_kcbnew_3], [0], [3303775], [4], [], [], [], [], [], [], [], []&#xff0c;导致过程无法正常执行 ORA-00600: 内部错误代码, 参数: [ktspffbmb:objdchk_kcbnew_3], [0], [3303775], [4]…...

SPINN:基于设备和云的神经网络协同递进推理

SPINN&#xff1a;基于设备和云的神经网络协同递进推理 论文标题&#xff1a;SPINN: synergistic progressive inference of neural networks over device and cloud 原文链接&#xff1a;https://dl.acm.org/doi/10.1145/3372224.3419194 论文动机 现代CNN过多的计算需求&am…...

数据结构-二叉树

数据结构-二叉树 二叉树的概念二叉树的遍历分类 建立二叉树&#xff0c;并遍历二叉树的最小单元二叉树的最小单元初始化初始化二叉树前序遍历的实现中序遍历的实现后序遍历的实现计算节点的个数计算树的深度求第k层的个数查找二叉树的元素分层遍历 全部代码如下 二叉树的概念 二…...

Open3D 进阶(4)高斯混合点云聚类

目录 一、算法原理1、原理概述2、实现流程3、参考文献二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。爬虫网站自重。 一、算法原理 1、原理概述 高斯混合聚类(GMM)算法假设数据点是由一个或多个高斯分布生成的,并通过最大似然估计的方法来估计每个簇…...