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.hqwc.cn/news/53612.html

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

相关文章

无涯教程-Lua - 函数声明

函数是一起执行任务的一组语句&#xff0c;您可以将代码分成单独的函数。 Lua语言提供了程序可以调用的许多内置方法。如方法 print()打印在控制台中作为输入传递的参数。 定义函数 Lua编程语言中方法定义的一般形式如下- optional_function_scope function function_name(…

React 论文《ReAct: Synergizing Reasoning and Acting in Language Models》阅读笔记

文章目录 1. 简介论文摘要翻译动机和主要贡献 2. REACT : SYNERGIZING *RE*ASONING *ACT*ING3. KNOWLEDGE-INTENSIVE REASONING TASKS3.1 设置3.2 方法3.3 结果和观察 4. 决策任务5. 参考资料 1. 简介 论文摘要翻译 虽然大型语言模型&#xff08;LLM&#xff09;在自然语言理…

原型链污染例题复现

一、什么是原型链 下面我们通过这个小例子来看看。 可以看到b在实例化为test对象以后&#xff0c;就可以输出test类中的属性a了。这是因为在于js中的一个重要的概念&#xff1a;继承。而继承的整个过程就称为该类的原型链。 在javascript中,每个对象的都有一个指向他的原型(p…

棱镜七彩正式加入龙蜥社区安全联盟(OASA)

近日&#xff0c;龙蜥社区安全联盟&#xff08;OASA&#xff09;正式成立&#xff0c;棱镜七彩成为该联盟成员单位。 龙蜥社区安全联盟是促进产业合作的非营利组织&#xff0c;致力于打造中立开放、聚焦操作系统信息安全的交流平台&#xff0c;推进龙蜥社区乃至整个产业安全生态…

antd 库的 Table 组件中删除一个或多个选中的列表

先解释一下原代码每个方法的含义 const TablePage: React.FC () > {/* selectedRowKeys 指定选中项的 key 数组&#xff0c;需要和 onChange 进行配合在此处&#xff0c;通过 rowSelection.selectedRowKeys 来控制选中项。*/const [selectedRowKeys, setSelectedRowKeys] …

msvcp120.dll丢失的解决方法(亲测可修复方的法)

在运行某些软件的时候&#xff0c;计算机提示msvcp120.dll丢失&#xff0c;无法打开运行软件。在第一次遇到这个问题的时候&#xff0c;相信很多人都不知道是怎么回事。下面小编把msvcp120.dll是什么以及如何解决这个问题的详细方法给大家科普一下。 问题描述&#xff1a; 在使…

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

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

4.PyCharm汉化

完成上一篇的安装之后&#xff0c;全英文的界面可能对一些英文不太好的小伙伴不太友好&#xff0c;本篇文章介绍Phcharm汉化教程&#xff1a; 点击菜单种的File-Setting 选择Marketplace在搜索框输入Chinese 点击安装 安装成功后会提示重新启动&#xff0c;点击Restart 安…

使用TensorBoard进行可视化

1. TensorBoard介绍 TensorBoard是TensorFlow推出的可视化工具&#xff0c;可以可视化模型结构、跟踪并以表格形式显示模型指标。 TensorBoard的使用包括两个步骤&#xff1a; 在代码中设置TensorBoard&#xff0c;在训练的过程中将会根据设置产生日志文件在浏览器中可视化该…

如何在轻量级RTSP服务支持H.264扩展SEI发送接收自定义数据?

为什么开发轻量级RTSP服务&#xff1f; 开发轻量级RTSP服务的目的是为了解决在某些场景下用户或开发者需要单独部署RTSP或RTMP服务的问题。这种服务的优势主要有以下几点&#xff1a; 便利性&#xff1a;通过轻量级RTSP服务&#xff0c;用户无需配置单独的服务器&#xff0c;…

【Linux后端服务器开发】Reactor模式实现网络计算器

目录 一、Reactor模式概述 二、日志模块&#xff1a;Log.hpp 三、TCP连接模块&#xff1a;Sock.hpp 四、非阻塞通信模块&#xff1a;Util.hpp 五、多路复用I/O模块&#xff1a;Epoller.hpp 六、协议定制模块&#xff1a;Protocol.hpp 七、服务器模块&#xff1a;Server.…

05 - ArrayList还是LinkedList?使用不当性能差千倍

集合作为一种存储数据的容器&#xff0c;是我们日常开发中使用最频繁的对象类型之一。JDK 为开发者提供了一系列的集合类型&#xff0c;这些集合类型使用不同的数据结构来实现。因此&#xff0c;不同的集合类型&#xff0c;使用场景也不同。 很多同学在面试的时候&#xff0c;…