EventBus 开源库学习(一)

news2024/10/3 8:24:46

一、概念

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";

    @Override
    public void onCreate() {
        super.onCreate();
        //注册数据监听
        EventBus.getDefault().register(this);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Subscribe
    public 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());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //解注册数据监听
        EventBus.getDefault().unregister(this);
    }
}

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

public class EventBusActivity extends AppCompatActivity {
    private static final String TAG = "Test_EventBusActivity";

    @Override
    protected 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() {
            @Override
            public void onClick(View view) {
                //发送数据给监听者
                EventBus.getDefault().post("msg1 - coming!!!");
            }
        });

        msg2Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //发送数据给监听者
                MsgEvent event = new MsgEvent("msg2 - coming!!!");
                EventBus.getDefault().post(event);
            }
        });
    }

    @Override
    protected 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;
    }

    @Override
    public 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() {
            @Override
            public void onClick(View view) {
                //发送数据给监听者
                new Thread(new Runnable() {
                    @Override
                    public 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() {
            @Override
            public void onClick(View view) {
                //发送数据给监听者
                new Thread(new Runnable() {
                    @Override
                    public 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() {
            @Override
            public 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() {
            @Override
            public 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() {
            @Override
            public 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() {
            @Override
            public void onClick(View view) {
                //发送数据给监听者
                new Thread(new Runnable() {
                    @Override
                    public 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() {
            @Override
            public 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() {
            @Override
            public void onClick(View view) {
                //发送数据给监听者
                new Thread(new Runnable() {
                    @Override
                    public 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.coloradmin.cn/o/835973.html

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

相关文章

Windows环境下VSCode安装PlatformIO Cero报错ERROR: HTTP error 403 while getting

安装PlatformIO插件成功&#xff0c;初始化失败 错误信息判断问题尝试访问https://pypi.tuna.tsinghua.edu.cn/simple/platformio/成功点击文件后报错如下&#xff1a; 解决问题- 换源 &#xff08; Windows下有两个地方需要更改&#xff09;cmd命令行Pip文件 总结&#xff1a;…

C语言指针操作数组赋值

1、通过指针修改数组元素的值 ps:int a[10] {10}; 数组名a &a[0] a1 &a[0]1 跨过得是数组元素类型的长度&#xff0c;&a是对整个数组取地址&#xff0c;&a1是跨过整个数组的长度 #include "stdio.h" #include <stdlib.h>int main() {i…

LeetCode-654-最大二叉树

一&#xff1a;题目描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回…

勒索软件攻击防御的9件事

什么是勒索软件攻击&#xff1f; 勒索软件是一种特定类型的恶意软件&#xff0c;它将数据作为“人质”来勒索赎金。网络钓鱼电子邮件是其一种常见的传播方式&#xff0c;同时勒索软件也可以借由下载广泛传播&#xff0c;也就是在用户访问受到感染的网站时进行传播。随着网络攻…

推荐GitHub 中的 C avl tree

https://github.com/greensky00/avltree.git 6 内核果然是,最好的C 标准库 &#x1f602;, 早晚手撕一遍这个代码

大模型,拼算力更拼落地力

近年来&#xff0c;随着人工智能领域的快速发展&#xff0c;大模型已经成为了业界热议的话题之一。在这个信息爆炸的时代&#xff0c;数据变得比以往任何时候都更加丰富&#xff0c;而大模型的兴起&#xff0c;为我们揭示了探索数据中蕴藏的价值和智慧提供了全新的途径。然而&a…

【阵列信号处理】空间匹配滤波器、锥形/非锥形最佳波束成形器、样本矩阵反演 (SMI) 研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Unity Shader编辑器工具类ShaderUtil 常用函数和用法

Unity Shader编辑器工具类ShaderUtil 常用函数和用法 Unity的Shader编辑器工具类ShaderUtil提供了一系列函数&#xff0c;用于编译、导入和管理着色器。本文将介绍ShaderUtil类中的常用函数和用法。 编译和导入函数 CompileShader 函数签名&#xff1a;public static bool C…

发灰黑行业用搜索留痕排名推广哪款软件好

发灰黑行业用搜索留痕排名推广哪款软件好 最近微博视频排名发不了&#xff0c;不收录 目前推荐泛目录或者寄生虫 以后只要知道这个逻辑就可以 平台会因为发的人多而和谐&#xff0c;也就是发不出去 接下来给大家介绍下 想要网站排名&#xff0c;却又不知道具体的优化步骤和方…

自建类ChatGPT服务:本地化部署与远程访问教程

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

基于注解实现接口幂等机制防止数据重复提交

1:什么是接口幂等性? 能解决什么问题? 接口幂等性是指无论调用接口的次数是一次还是多次&#xff0c;对于同一资源的操作都只会产生相同的效果。 比如: 一个订单记账的时候,会同步扣减库存数量,如果记账的按钮被用户多次触发,就会导致一个订单库存却被多次扣减的情况. 如果对…

【ArcGIS Pro二次开发】(56):界址点导出Excel

界址点成果表是地籍测绘中的一种表格&#xff0c;用于记录地块的界址点坐标和相关属性信息。 这个工具的目的就是为了将地块要素导出为界址点成果表。 一、要实现的功能 如上图所示&#xff0c;在【数据处理】组—【Excel相关】面板下&#xff0c;点击【界址点导出Excel】工具。…

话费充值系统源码话费直充快充慢充系统源码

话费充值系统/话费直充/快充慢充系统/话费直充系统

seaborn绘制热力图

目录 1、普通绘制热力图 2、坐标轴标签太多&#xff0c;自定义标签显示 3、不显示热图的网格 1、普通绘制热力图 # -*- coding:utf-8 _*- import numpy as np import seaborn as sns import matplotlib.pyplot as plt# 创建数据 data np.random.random((7,12)) # 计算相关…

Shell脚本学习-循环的控制命令

break continue exit对比&#xff1a; 示例1&#xff1a;break命令跳出整个循环。 [rootabc scripts]# cat break1.sh #!/bin/bashfor((i0;i<5;i)) doif [ $i -eq 3 ]thenbreakfiecho $i done echo "ok"[rootabc scripts]# sh break1.sh 0 1 2 ok可以看到i等于3及…

NetMizer 日志管理未授权访问+FTP登录

漏洞描述 北京灵州网络技术有限公司NetMizer日志管理系统存在目录遍历漏洞&#xff0c;由于 /data 控制不严格&#xff0c;攻击者可利用该漏洞获取敏感信息。 免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络应当遵守宪法法律&#xff0c;遵守公共秩序&#…

Visual Studio Code中对打开的脚本格式统一

什么是Language Server Protocol (LSP)? Language Server Protocol&#xff08;语言服务器协议&#xff0c;简称LSP&#xff09;是微软在2016年提出的一套统一的通讯协议方案。LSP定义了一套编辑器或者IDE与语言服务器&#xff08;Language Server&#xff09;之间使用的协议&…

openlayers渲染rgb三波段cog时达到类似rgba的效果(去掉黑底)

图是arcgis渲染成rgb的&#xff0c;由于没有透明度波段&#xff0c;底下是黑的。 为了能在前端显示透明效果&#xff0c;之前是用python处理数据&#xff0c;给它加个透明度波段 后来研究了一下ol的样式表达式&#xff0c;可以直接在前端去掉黑底 样式设置代码如下 const s…

Vue读取本地静态.md并侧边栏导航跳转、展示.md文件

vue markdown 侧边栏导航跳转 类似锚点跳转 - 灰信网&#xff08;软件开发博客聚合&#xff09; Vue使用mavon-editor插件解析markdown编辑预览_onpine的博客-CSDN博客 vue组件直接读取.md文档展示_vue项目中读取readme文件_小蒜瓣的博客-CSDN博客vue中使用mavonEditor(markd…

华秋亮相2023世界汽车制造技术暨智能装备博览会,推动汽车产业快速发展

洞悉全球汽车产业格局&#xff0c;前瞻业界未来趋势。2023年7月27日-30日&#xff0c;时隔三年&#xff0c;重聚武汉国际博览中心&#xff0c;2023世界汽车制造技术暨智能装备博览会盛大开幕。深耕汽车行业多年的世界汽车制造技术暨智能装备博览会&#xff0c;掀起行业热点新高…