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详解 (详解 + 原理)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

chrome扩展在popup、background、content之间通信解决传输文件问题

文章目录 背景介绍案例介绍代码示例popup页面&#xff0c;上传文件页面popup页面&#xff0c;js上传代码&#xff0c;file文件转base64background监听消息&#xff0c;base64转file文件&#xff0c;axios上传 附-转base64后直接下载 背景介绍 示例扩展API版本MV2。 以弹…

新增数据自动生成递增排序序号

明确的点 获取序号数组&#xff0c;如果有缺失正整数&#xff0c;则获取最小缺失正整数作为序号 如果没有缺失&#xff0c;则获取序号最大值1作为新的序号 每次生成新序号需要push到序号数组 每次移除数据&#xff0c;需要删除序号数组中对应值的一条记录 1 获取序号数组 //记…

SQL-每日一题【1193. 每月交易 I】

题目 Table: Transactions 编写一个 sql 查询来查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数及其总金额。 以 任意顺序 返回结果表。 查询结果格式如下所示。 示例 1: 解题思路 1.题目要求我们查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数…

Spring Cloud Eureka 和 zookeeper 的区别

CAP理论 在了解eureka和zookeeper区别之前&#xff0c;我们先来了解一下这个知识&#xff0c;cap理论。 1998年的加州大学的计算机科学家 Eric Brewer 提出&#xff0c;分布式有三个指标。Consistency&#xff0c;Availability&#xff0c;Partition tolerance。简称即为CAP。…

【知识图谱】图数据库Neo4jDesktop的安装图文详解(小白适用)

neo4j 的安装需要有jdk环境的支持。因此在安装Neo4j之前&#xff0c;需要安装Java JDK。 一.安装JDK 参考文章https://blog.csdn.net/weixin_41824534/article/details/104147067?spm1001.2014.3001.5502 二.Neo4j下载 进入Neo4j官网 选择下载中心 下滑选择Neo4j Deskto…

uniapp引入inconfont

app,h5端引入 uniapp本身的全局设置中有个iconfontsrc属性 所以只需要 1.iconfont将需要的icon添加至项目 2.下载到本地解压后,将其中的ttf文件,放在static静态目录下 3.在page.json中对全局文件进行配置tabBar(导航图标) “iconfontSrc”: “static/font/iconfont.ttf”, …

【iOS】App仿写--天气预报

文章目录 前言一、首页二、搜索界面三、添加界面四、浏览界面总结 前言 最近完成了暑假的最后一个任务——天气预报&#xff0c;特此记录博客总结。根据iPhone中天气App的功能大致可以将仿写的App分为四个界面——首页&#xff0c;搜索界面&#xff0c;添加界面&#xff0c;浏…

blender的下载安装和配置中文环境

引言 在3D建模和动画设计领域&#xff0c;Blender 作为一款强大且免费的开源软件&#xff0c;一直以优秀的性能和对众多技术的支持赢得了大批用户的喜爱。然而&#xff0c;对于刚接触这款软件的用户而言&#xff0c;其安装和配置过程可能会带来一定困扰&#xff0c;尤其是在设…

Leetcode-每日一题【剑指 Offer 04. 二维数组中的查找】

题目 在一个 n * m 的二维数组中&#xff0c;每一行都按照从左到右 非递减 的顺序排序&#xff0c;每一列都按照从上到下 非递减 的顺序排序。请完成一个高效的函数&#xff0c;输入这样的一个二维数组和一个整数&#xff0c;判断数组中是否含有该整数。 示例: 现有矩阵 matri…

公文写作技巧:“三面镜子”写作提纲60例

写作技巧&#xff1a;“三面镜子”写作提纲60例 1. 用好“三面镜子” 推深做实警示教育 勤用“反光镜”以案为鉴。 善用“显微镜”以案明纪。 巧用“聚光镜”以案促改。 2. 年轻干部要用好“三面镜子” 用好“反光镜”&#xff0c;照亮基层中的“暗点” 用好“显微镜”&am…

掌握Memory Profiler技巧:识别内存问题

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、如何使用四、页面说明4.1 Java 和 Kotlin 分配…

命令模式——请求发送者与接收者解耦

1、简介 1.1、概述 在软件开发中&#xff0c;经常需要向某些对象发送请求&#xff08;调用其中的某个或某些方法&#xff09;&#xff0c;但是并不知道请求的接收者是谁&#xff0c;也不知道被请求的操作是哪个。此时&#xff0c;特别希望能够以一种松耦合的方式来设计软件&a…

十四.redis哨兵模式

redis哨兵模式 1.概述2.测试3.哨兵模式优缺点 redis哨兵模式基础是主从复制 1.概述 主从切换的技术方法&#xff1a;当主节点服务器宕机后&#xff0c;需要手动把一台从服务器切换为主服务器&#xff0c;这就需要人工干预&#xff0c;费时费力&#xff0c;还会造成一段时间内服…

【N32L40X】学习笔记13-软件IIC读写EEPROM AT24C02

AT24C02 8个字节每页,累计32个页 通讯频率MAX 400K AT24C02大小 2K 芯片地址 对于at24c02 A2A1A0 这三个引脚没有使用 写时序 由于设备在写周期中不会产生ACK恢复&#xff0c;因此这可用于确定周期何时完成&#xff08;此特性可用于最大限度地提高总线吞吐量&#xff09;…

机器学习笔记 - YOLO-NAS 最高效的目标检测算法之一

一、YOLO-NAS概述 YOLO(You Only Look Once)是一种对象检测算法,它使用深度神经网络模型,特别是卷积神经网络,来实时检测和分类对象。该算法首次在 2016 年由 Joseph Redmon、Santosh Divvala、Ross Girshick 和 Ali Farhadi 发表的论文《You Only Look Once: Unified, Re…

2023-08-05——JVM 栈

栈 stack 栈&#xff1a;数据结构 程序数据结构算法 栈&#xff1a;先进后出&#xff0c;后进先出 好比一个&#xff1a;桶 队列&#xff1a;先进先出&#xff08;FIFO &#xff1a;First Input First Out&#xff09; 好比一个&#xff1a;管道 栈&#xff1a;喝多了吐。队列…

抽象轻松JavaScript

随心所欲的数组切割与改变2.0版本 splice(开始位置&#xff0c;删除数量&#xff0c;添加内容) slice(开始位置&#xff0c;结束位置) 目的&#xff0c;上面的一串小字&#xff0c;切割与改变 切割代表删&#xff0c;改变代表增、改&#xff0c;随心所欲的切割与改变意味着不…

分布式应用:Zookeeper 集群与kafka 集群部署

目录 一、理论 1.Zookeeper 2.部署 Zookeeper 集群 3.消息队列 4.Kafka 5.部署 kafka 集群 6.FilebeatKafkaELK 二、实验 1.Zookeeper 集群部署 2.kafka集群部署 3.FilebeatKafkaELK 三、问题 1.解压文件异常 2.kafka集群建立失败 3.启动 filebeat报错 4.VIM报错…

页面技术基础-html

页面技术基础-html 环境准备&#xff1a;在JDBC中项目上完成代码定义 1. 新建一个 Module:filr->右键 -》Module -》Java-》next->名字(html_day1)->finish 2. 在 Moudle上右键-》第二个选项&#xff1a;add framework .. -> 选择JavaEE下第一个选项 Web Apllicat…

mysql高级(尚硅谷-夏磊)

目录 内容介绍 Linux下MySQL的安装与使用 Mysql逻辑架构 Mysql存储引擎 Sql预热 索引简介 内容介绍 1、Linux下MySQL的安装与使用 2、逻辑架构 3、sql预热 Linux下MySQL的安装与使用 1、docker安装docker run -d \-p 3309:3306 \-v /atguigu/mysql/mysql8/conf:/etc/my…