当前位置: 首页 > 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详解 (详解 + 原理)

http://www.lryc.cn/news/112551.html

相关文章:

  • 车载以太网SOME/IP的个人总结
  • vue2.29-Vue3跟vue2的区别
  • 【深度学习】分类和分割常见损失函数
  • Redhat Linux 安装MySQL安装手册
  • 题目:2303.计算应缴税款总额
  • Kotlin 1.9.0 发布:带来多项新特性,改进 Multiplatform/Native 支持
  • 接口测试——认知(一)
  • 剑指 Offer 10- I. 斐波那契数列
  • 洪水填充算法详解
  • ubuntu18.04安装docker及docker基本命令的使用
  • DataWhale 机器学习夏令营第二期——AI量化模型预测挑战赛 学习记录
  • 简单认识ELK日志分析系统
  • 【算法笔记】深度优先遍历-解决排列组合问题-
  • 【雕爷学编程】Arduino动手做(184)---快餐盒盖,极低成本搭建机器人实验平台2
  • 应急响应-勒索病毒的处理思路
  • ChatGPT是否能够处理多模态数据和多模态对话?
  • AcWing1171. 距离(lcatarjan)
  • JVM-运行时数据区
  • RedisTemplate中boundHashOps的使用
  • 计算机网络-性能指标
  • 排序第一课【插入排序】直接插入排序 与 希尔排序
  • 云计算——ACA学习 云计算概述
  • 如何为网站进行全面的整站翻译?
  • 项目部署(前后端分离)
  • 增强型Web安全网关在银行的应用
  • Oracle-ORA-00600:[ktspffbmb:objdchk_kcbnew_3]
  • SPINN:基于设备和云的神经网络协同递进推理
  • 数据结构-二叉树
  • Open3D 进阶(4)高斯混合点云聚类
  • 计算机组成和IO