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

    @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.mfbz.cn/a/61753.html

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

相关文章

插入排序讲解

插入排序&#xff08;Insertion-Sort&#xff09;一般也被称为直接插入排序。对于少量元素的排序&#xff0c;它是一个有效的算法。插入排序是一种最简单的排序方法&#xff0c;它的基本思想是将一个记录插入到已经排好序的有序表中&#xff0c;从而一个新的、记录数增1的有序表…

【Linux命令详解 | pwd命令】Linux系统中用于显示当前工作目录的命令

文章标题 简介一&#xff0c;参数列表二&#xff0c;使用介绍1. pwd命令的基本使用2. pwd命令中的参数3. pwd命令的工作机制4. pwd命令的实际应用 总结 简介 pwd命令是Linux中的基础命令之一&#xff0c;使用该命令可以快速查看当前工作目录。在掌握Linux命令时&#xff0c;pw…

golang函数传参——值传递理解

做了五年的go开发&#xff0c;却并没有什么成长&#xff0c;都停留在了业务层面了。一直以为golang中函数传参&#xff0c;如果传的是引用类型&#xff0c;则是以引用传递&#xff0c;造成这样的误解&#xff0c;实在也不能怪我。我们来看一个例子&#xff0c;众所周知&#xf…

单例模式(C++)

定义 保证一个类仅有一个实例&#xff0c;并提供一个该实例的全局访问点。 应用场景 在软件系统中&#xff0c;经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例&#xff0c;才能确保它们的逻辑正确性、以及良好的效率。如何绕过常规的构造器&#xff0c;提供一种…

微信小程序iconfont真机渲染失败

解决方法&#xff1a; 1.将下载的.woff文件在transfonter转为base64&#xff0c; 2.打开网站&#xff0c;导入文件&#xff0c;开启base64按钮&#xff0c;下载转换后的文件 3. 在下载解压后的文件夹中找到stylesheet.css&#xff0c;并复制其中的base64 4. 修改index.wxss文…

Netty:当Channel将数据发送成功以后,存放发送数据的ByteBuf会被自动释放

说明 使用Netty框架编程&#xff0c;当Channel将数据发送成功以后&#xff0c;存放发送数据的ByteBuf会被自动释放。 为了进行验证&#xff0c;我们可以在发送数据前&#xff0c;通过io.netty.buffer.ByteBuf的refCnt()函数看看引用计数&#xff0c;通过Channel发送成功以后再…

(数据库系统概论|王珊)第一章绪论-第一节:数据库系统概论

目录 一&#xff1a;四大基本概念 &#xff08;1&#xff09;数据(Data) &#xff08;2&#xff09;数据库(DataBase,DB) &#xff08;3&#xff09;数据库管理系统(DataBase Management System,DBMS) &#xff08;4&#xff09;数据库系统(Database System&#xff0c;DBS…

Laravel 框架路由参数.重定向.视图回退.当前路由.单行为 ②

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; THINK PHP &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f44…

Nios初体验之——Hello world!

文章目录 前言一、系统设计1、系统模块框图2、系统涉及到的模块1、时钟2、nios2_qsys3、片内存储&#xff08;onchip_rom、onchip_ram&#xff09;4、串行通信&#xff08;jtag_uart&#xff09;5、System ID&#xff08;sysid_qsys&#xff09; 二、硬件设计1、创建Qsys2、重命…

VGGNet剪枝实战:使用VGGNet训练、稀疏训练、剪枝、微调等,剪枝出只有3M的模型

摘要 本文讲解如何实现VGGNet的剪枝操作。剪枝的原理&#xff1a;在BN层网络中加入稀疏因子&#xff0c;训练使得BN层稀疏化&#xff0c;对稀疏训练的后的模型中所有BN层权重进行统计排序&#xff0c;获取指定保留BN层数量即取得排序后权重阈值thres。遍历模型中的BN层权重&am…

MySQL事务管理

MySQL事务管理 MySQL增删查改时的问题一.什么是事务&#xff1f;二.为什么会出现事务&#xff1f;三.事务的其他属性1. 事务的版本支持2. 事务的提交方式 四.事务的准备工作五.事务的操作1. 事务的正常操作2. 事务的异常验证与产出结论 六.事务的隔离级别1. 事务隔离级别概念2.…

CentOS 安装 Jenkins

本文目录 1. 安装 JDK2. 获取 Jenkins 安装包3. 将安装包上传到服务器4. 修改 Jenkins 配置5. 启动 Jenkins6. 打开浏览器访问7. 获取并输入 admin 账户密码8. 跳过插件安装9. 添加管理员账户 1. 安装 JDK Jenkins 需要依赖 JDK&#xff0c;所以先安装 JDK1.8。输入以下命令&a…

如何打造属于自己的个人IP?

在当今信息爆炸的时代&#xff0c;个人 IP 已经成为人们在网络世界中的独特标签。无论是在职场上、创业中&#xff0c;还是在社交生活中&#xff0c;拥有个人 IP 的人都能脱颖而出&#xff0c;吸引更多的关注和机会。那么&#xff0c;如何打造属于自己的个人 IP 呢&#xff1f;…

PowerShell 中,你可以使用以下命令来获取磁盘、内存、CPU、GPU、网卡和声卡的硬件信息

在 PowerShell 中&#xff0c;你可以使用以下命令来获取磁盘、内存、CPU、GPU、网卡和声卡的硬件信息&#xff1a; 获取磁盘信息&#xff1a; Get-PhysicalDisk | Select-Object DeviceID, MediaType, Model, Size获取内存信息&#xff1a; Get-CimInstance Win32_PhysicalM…

中兴服务器支持百度“文心一言”,助力AI产业发展

前段时间&#xff0c;中兴和百度正式对外宣布中兴服务器将会支持百度“文心一言”&#xff0c;为其提供更加强劲的算力支撑&#xff0c;从而加速“文心一言”的完事升级与更新迭代&#xff0c;助力AI产业化应用和生态的繁荣发展。   “文心一言”是百度基于文心大模型技术推出…

【docker】docker-compose服务编排

目录 一、服务编排概念二、docker compose2.1 定义2.2 使用步骤2.3 docker-compose安装2.4 docker-compose卸载 三、编排示例 一、服务编排概念 1.微服务架构的应用系统中一般包含若干个微服务&#xff0c;每个微服务一般都会部署多个实例&#xff0c;如果每个微服务都要手动启…

0-1搭建vue项目工程

一、下载node.js 简单介绍&#xff1a; Node.js是一个基于V8引擎的JavaScript运行时环境&#xff0c;它允许开发者在服务器端使用JavaScript进行开发。Node.js是一个非常强大的工具&#xff0c;可以帮助开发者构建高性能、可扩展的Web应用程序&#xff0c;并且可以与各种技术…

Gitlab CI/CD笔记-第二天-GitOps的流水线常用关键词(1)

一、常用关键词 在Gitlab项目的根目录需要创建一个 .gitlab-ci.yaml的文件。 这个文件就是定义的流水线。Call :"Pipeline as code" 二、这条流水线怎么写&#xff1f; 一、掌握常用的关键词即可。 1.关键词分类 1.全局关键词 Global Keywards 2.任务关键词…

长度最小的子数组_力扣209

文章目录 题目描述法一 滑动窗口法题目描述 法一 滑动窗口法 int minSubArrayLen(int target, vector<int>&nums){int
最新文章