Android中EventBus简单使用

news/2024/9/29 9:25:35

综述

消息总线又叫事件总线, 被广泛的应用于各类项目之中. 但是此处只概述Android体系中用到的框架. 为什么项目会需要一个消息总线呢? 一句话概括, 在大多数常见项目中, 随着项目变大, 项目可能出现大量的跨页面, 跨组件, 跨线程, 跨进程来传递消息与数据的需求. 为了更方便的直接通知到指定的页面实现具体的逻辑, 工程师们发展了消息总线体系来解决这一类问题, 因此如今我们可以在其它工程师的工作基础上简单的实现我们想要的功能.

现在是2023年, 从现在往前推10年, 这期间Android体系中被广泛使用的主流消息总线框架大致有如下几种:

  • 首先是Android原生的 Broadcast 以及 BroadcastReceiver 体系. 这是Android中最原始也最笨重的事件总线.
  • 接着是 GreenRobot 公司出品的 EventBus 和开发者们使用 RxJava 库封装的 RxBus 相互竞争. 一者简单易学上限低, 一者强大复杂难入门.
  • 然后流行的是使用官方出品的 Android Jetpack 库中的 livedata 组件封装的 LiveDataBus.
  • 最新开始广泛使用的消息总线则是使用SharedFlow封装的 FlowBus.

所以, 回到本文的核心, 从某种意义上说, Eventbus处于一个承上启下的位置. 相较于原生的广播体系它简化了组件间的通信, 提高了开发效率, 又因为其流行时间较早而广泛的应用于大量早期开发的android项目中, 没有 RxBus 强大的功能既是缺点也是优点, 因为这样也就没有过于复杂的上手难度. 唯一值得诟病的是消息发送和接收没有一个统一的管理或者配置中心, 一旦大规模使用会非常繁杂, 使得其在大型和超大型项目中难以维护.

因此, 我整理并记录这篇文章, 方便在日后需要时进行回顾.

概念

以下为GreenRobot官方给出的EventBus消息传递示意图

此图描述使用eventbus传递一次消息所涉及的四个角色, 即

  1. 发布者, 也就是Publisher, 负责发送消息.
  2. 订阅者, 也就是Subscriber, 负责接收消息.
  3. 事件, 也就是Event, 即存放信息的事件对象.
  4. EventBus, 可以理解为中转站, 事件从发布者通过EventBus发送到订阅者那里.

在使用时, 需要工程师自己实现的仅有前三个角色. 中转站本身EventBus库已经自行实现.

使用方法

添加依赖

使用前, 需要引入相关的库, 在gradle中加入

implementation("org.greenrobot:eventbus:3.3.1")
//或者是java版本
implementation("org.greenrobot:eventbus-java:3.3.1")

如果使用的是maven则在依赖中加入

<dependency><groupId>org.greenrobot</groupId><artifactId>eventbus-java</artifactId><version>3.3.1</version>
</dependency>

其它的比如将jar包引入项目的做法此处略过.

简单使用

首先需要定义一个事件Event, 这个类一般单独定义

//java版本
public class MessageEvent {public final String message;public MessageEvent(String message) {this.message = message;}
}

然后定义一个订阅者, 这个方法一般会放在需要接受信息的类中, 以下两个示例分别对应使用主线程(UI线程)传递和处理事件, 以及使用当前发布者所在的线程(无论是哪个线程)传递和处理事件时的做法.

//java版本
// This method will be called when a MessageEvent is posted (in the UI thread for Toast)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {doSomethingWith(event);
}

同时, 定义的订阅者方法的类需要被注册才能被eventbus知晓, 在有生命周期回调的类比如fragment或者activity中使用订阅者一般在生命周期中注册和注销订阅者所在的类. 而没有生命周期回调的类比如repo或者datasource, 一般会在初始化时注册订阅者, 在类被主动销毁时注销订阅者(或者干脆不注销, 使用单例模式加上app运行结束系统自动关闭).
注意: 订阅者方法必须为public, 且无论是缺了注册注销还是缺了订阅者方法都可能导致app报错

//java版本
@Override
public void onStart() {super.onStart();EventBus.getDefault().register(this);
}@Override
public void onStop() {EventBus.getDefault().unregister(this);super.onStop();
}

最后, 需要定义一个发布者, 发布者非常简单, 只是一条简单的指令, 在任何需要发送数据的地方直接调用即可

//java版本
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

拓展功能介绍

订阅方式

在实现订阅者的时候除了默认的使用 @Subscriber 注解指定订阅者方法的做法之外, 还可以使用拓展功能同时指定消息传输的线程
使用如下方式

//默认方式
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {doSomethingWith(event);
}
//拓展方式// Called in the same thread (default)
// ThreadMode is optional here
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {log(event.message);
}// Called in a separate thread
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){backend.send(event.message);
}// Called in Android UI's main thread
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {textField.setText(event.message);
}// Called in Android UI's main thread
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMessage(MessageEvent event) {textField.setText(event.message);
}// Called in the background thread
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){saveToDisk(event.message);
}
  • 其中使用 @Subscribe(threadMode = ThreadMode.POSTING) 等同于使用 @Subscribe, 或者说后者就是前者的简写.
  • 使用 @Subscribe(threadMode = ThreadMode.MAIN) 表示订阅者方法将在android的主线程即UI线程中被调用, 一般用来处理和UI有关的操作.
  • 使用 @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) 将使得事件会严格的按照调用的顺序通过UI线程排队发送给订阅者.
  • 使用 @Subscribe(threadMode = ThreadMode.BACKGROUND) 表示如果发布者不是在主线程发布的事件则直接发送给订阅者, 如果发布方法在主线程发布的事件, eventbus将使用后台线程单独发送事件.
  • 使用 @Subscribe(threadMode = ThreadMode.ASYNC) 表示EventBus将始终使用另外的单独线程将事件发送给订阅者方法, 无论发布者是在哪个线程发送的事件.

粘性事件

粘性事件是一种特殊的事件, 常规来说, 一般发布者发送出去的事件如果发送后订阅者才注册, 那么新注册的订阅者是不会收到发送者发送的数据. 但是如果处于特殊场景下, 项目需要订阅者在注册后接收注册前已经发出的信息, 就可以使用粘性事件.

考虑以下假想场景:
一个项目需要和远程服务器进行连接并且隔一段时间动态获取数据并更新在activity界面, 所以使用了service进行持续的自动运行.
由于数据更新在ui上, 所以设置为activity处于onResume()时开启service, activity处于onPause()时停止service. 因为有时候用户会需要立刻刷新数据而不是等几十秒再刷新, 所以设置使用eventbus通知service终止当前的循环处理, 重新且立刻开始间隔一段时候就访问一次服务器数据的流程. 同时还存在另一个功能需求, 每次调用均需要动态申请系统权限并获取用户的许可.
好, 假设现在需要在获取用户许可后立刻通知服务器刷新. 那么就会存在获取用户许可时因为调用的是系统窗口, activity处于onstop()回调周期, service停止. 用户点击确定后, service可能已经开启也可能尚未重新初始化并注册订阅者.
所以, 此时通过权限申请回调运行发布者的指令会时不时无效.而在以上场景中, 使用粘性事件会是一种比较好的解决方案.

首先还是需要定义一个事件, 这一点和常规的事件的发送没有区别

//注意, 事件命名在语法上是自由的, 但是为了可读性, 一般会从XXXEvent改为StickyXXXEvent或者XXXStickyEvent
public class StickyMessageEvent {public final String message;public MessageEvent(String message) {this.message = message;}
}

定义一个发布者

//定义发布者
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));

最后定义一个接收者

//定义接收者
@Override
public void onStart() {super.onStart();EventBus.getDefault().register(this);
}// UI updates must run on MainThread
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {   textField.setText(event.message);
}@Override
public void onStop() {EventBus.getDefault().unregister(this);    super.onStop();
}

额外的, 因为粘性事件会长期存放在eventbus中, 一般在接收之后需要将其清除

//一般放在onEvent()中获取事件并处理后再执行
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {// "Consume" the sticky eventEventBus.getDefault().removeStickyEvent(stickyEvent);// Now do something with it
}

总结

以上就是eventbus的用法的简单整理, 一般性的使用差不多只需要这些功能. 其它的像是property, configuration, 取消发送之类的功能一般不会用到.
同时需要额外注意, 使用3.0之前的eventbus版本时, 在app打包时, 对eventbus相关方法进行混淆代码可能导致eventbus无法正常工作, 需要在混淆中单独设置规则以避开. 而3.0之后(包括3.0)的eventbus已经采用了新机制, 不需要对此进行额外的处理.

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

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

相关文章

记录--N 个值得一看的前端代码片段

🧑‍💻 写在开头 点赞 + 收藏 === 学会🤣🤣🤣在日常的开发过程中,我们都会有一些常用的代码片段,这些代码片段可以直接复制到各个项目中使用,非常方便。如果你有接手过别人的项目,就可以很明显感受到几个项目一般都会有一些相同的工具类方法,这些方法就是之前开…

2024.06 PET父母效能【扩大无问题区】

参考:https://www.jianshu.com/p/1676653be220 PART1:父母也是一个平凡的人,做真实的父母 关注关系,而非问题 父母不需要为每个问题负责 PART2:孩子有问题:积极的倾听,门把手法,让孩子自己发现问题,解决问题接纳孩子,更要接纳自己PART3:父母有问题:面质技巧 1.清楚界…

2024.06PET父母效能

参考:https://www.jianshu.com/p/1676653be220 PART1:父母也是一个平凡的人,做真实的父母 关注关系,而非问题 父母不需要为每个问题负责 PART2:孩子有问题:积极的倾听,门把手法,让孩子自己发现问题,解决问题接纳孩子,更要接纳自己PART3:父母有问题:面质技巧 1.清楚界…

SpringBoot集成devtools实现热部署调试

SpringBoot集成devtools实现热部署调试 简述 参考多篇网上文章终于实现热部署,中间出现过更改的文件已加载,但是并未自动重启的情况。由于判断不出哪些操作时多余的,记录了所有修改项 操作步骤 1.pom文件中增加依赖<dependency><groupId>org.springframework.bo…

【专题】2024绿色供应链白皮书报告合集PDF分享(附原数据表)

原文链接:https://tecdat.cn/?p=36468 原文出处:拓端数据部落公众号 最新的调研数据揭示,大部分企业已经深刻认识到供应链在环境、社会与治理(ESG)领域的重要性,并已经开始付诸实践。尽管如此,企业在供应链ESG的成熟度上仍有显著的进步空间,其中供应链伙伴间的协同合作…

Python遗传算法GA对长短期记忆LSTM深度学习模型超参数调优分析司机数据

全文链接:https://tecdat.cn/?p=36004 原文出处:拓端数据部落公众号 随着大数据时代的来临,深度学习技术在各个领域中得到了广泛的应用。长短期记忆(LSTM)网络作为深度学习领域中的一种重要模型,因其对序列数据的强大处理能力,在自然语言处理、时间序列预测等领域中取得…

【视频讲解】LSTM神经网络模型在微博中文文本评论情感分析和股市预测应用附代码数据

全文链接:https://tecdat.cn/?p=36471 原文出处:拓端数据部落公众号 分析师:Shuai Fung 本文将通过视频讲解,展示如何用python的LSTM模型对中文文本评论情感分析,并结合一个TensorFlow的长短期记忆神经网络(LSTM)、指数移动平均法预测股票市场和可视化实例的代码数据,为…

18.9k star!一个高性能的嵌入式分析型数据库,主要用于数据分析和数据处理任务。

大家好,今天给大家分享的是一个开源的面向列的关系数据库管理系统(RDBMS)。DuckDB是一个嵌入式的分析型数据库,它提供了高性能的数据分析和数据处理能力。DuckDB的设计目标是为数据科学家、分析师和数据工程师提供一个快速、灵活且易于使用的数据分析工具。它支持SQL查询语言…