简介

EventBus 是一个用于 Android 和 Java 编程的 事件发布/订阅框架。使用 EventBus 进行事件传递,事件的发布订阅就被充分解耦合,这使得编程人员从传统而原始的事件传递方式(诸如Handler、BroadcastReceiver、Interface回调等方式)中解放出来,专注业务逻辑的处理,有助于开发更加优美的程序。

基本概念

  • 事件(Event):也称为消息(Message),一个事件就是一个对象,这个对象里包含着此事件要传递的信息。一类事件属于一个类,不同类型的事件对象所属的类不同。事件有两种类型:

    • 一般事件。一般事件使用时,事件的订阅要在事件的发布之前。
    • 粘滞事件(Sticky Events):如果希望某未订阅事件在发布之后,再订阅该事件时依然能收到该事件,使用粘滞事件。
  • 发布者(Publisher):通常指的是发布某类事件的类。

  • 订阅者(Subscriber):通常指的是订阅某类事件的类。当发布者发布某事件后,EventBus会执行已订阅此事件的订阅者方法,该方法也叫事件处理方法。订阅者须先从 EventBus 注册(register)自身之后才能收到事件。除注册外,还有反注册(unregister)。反注册之后,订阅者不会再收到事件。Android中,如果订阅者是Activity或Fragment,注册和反注册通常根据生命周期来进行。

基本用法

以 Android 中的使用进行介绍。

  1. 添加依赖。

    implementation 'org.greenrobot:eventbus:3.2.0'
  2. 定义事件。事件为无特定要求的 POJO(plain old Java object,简单Java对象)。

    public class MessageEvent {
    
        public final String message;
    
        public MessageEvent(String message) {
    this.message = message;
    }
    }
  3. 指定订阅者。订阅者需要实现事件处理方法(使用@Subscribe注解),以便在事件发布时被调用。自 EventBus 3.0 开始,事件处理方法名称可以任意指定。

    // 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();
    }

    此外,订阅者还需要从 EventBus 注册 和 反注册 自身。订阅者只有注册自身之后,才可能会收到事件。

    // 根据生命周期注册和反注册
    @Override
    public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
    } @Override
    public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
    }
  4. 发布事件。发布者可以在代码的任何位置发布事件。事件发布后,所有与当前类型事件匹配的已注册订阅者都可以收到该事件。

    EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

高级用法

线程模式(ThreadMode)

EventBus 提供了5个不同的线程模式,用于在与事件发布线程相同或不同的线程中调用订阅者方法。

  1. POSTING

    订阅者将在与发布事件的同一线程中被调用,此为EventBus默认线程模式。事件发布以后立即调用订阅者,且线程不进行切换。该模式要求订阅者方法应快速返回,以避免阻塞发布线程。

    // threadMode 项 可不指定
    @Subscribe(threadMode = ThreadMode.POSTING)
    public void onMessage(MessageEvent event) {
    log(event.message);
    }
  2. MAIN

    订阅者将在Android的主线程(UI线程)中调用。如果发布线程是主线程,此处用法与POSTING模式相同。此处事件处理将会阻塞事件产生,即事件一旦被发布,发布者代码不再往下运行,除非订阅者方法执行完毕。该模式要求订阅者方法应快速返回,以避免阻塞主线程。如果发布线程不是主线程,事件将排入队列。

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessage(MessageEvent event) {
    textField.setText(event.message);
    }
  3. MAIN_ORDERED

    订阅者将在Android的主线程(UI线程)中调用。事件始终排入队列,以便在稍后传递给订阅者,因此发布事件的调用将立即返回,订阅者方法执行将在发布事件调用结束之后。该模式使事件处理拥有更严格和更一致的顺序。

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void onMessage(MessageEvent event) {
    textField.setText(event.message);
    }
  4. BACK_GROUND

    订阅者将在后台线程(子线程)中被调用。如果发布线程不是主线程,订阅者方法将直接在发布线程中调用。如果发布线程是主线程, EventBus将使用单个后台线程按顺序传递其所有事件。该模式要求订阅者方法应快速返回,以避免阻塞后台线程。

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onMessage(MessageEvent event){
    saveToDisk(event.message);
    }
  5. ASYNC

    订阅者方法在单独的线程中被调用,此线程在主线程和发布线程之外。发布线程永远不会阻塞,因为其不等待使用此模式的订阅者方法的返回。如果订阅者方法的执行需要一些时间,使用此模式。

    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onMessage(MessageEvent event){
    backend.send(event.message);
    }

粘滞事件(Sticky Events)

事件是粘滞事件与否,由发布者发布事件时使用的方法决定:

EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
  • post():发布一般事件
  • postSticky():发布粘滞事件。

某粘滞事件发布后,在订阅者注册期间,当其订阅者方法使用了粘滞事件的标记时,EventBus会将已保留在内存中的此类事件的最后一个事件发送给此订阅者方法。

允许手动获取和删除粘滞事件:

MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// "Consume" the sticky event
EventBus.getDefault().removeStickyEvent(stickyEvent);
// Now do something with it
}

粘滞事件的标记:

@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
textField.setText(event.message);
}

EventBus 简明教程的更多相关文章

  1. 2013 duilib入门简明教程 -- 第一个程序 Hello World(3)

    小伙伴们有点迫不及待了么,来看一看Hello World吧: 新建一个空的win32项目,新建一个main.cpp文件,将以下代码复制进去: #include <windows.h> #i ...

  2. 2013 duilib入门简明教程 -- 部分bug (11)

     一.WindowImplBase的bug     在第8个教程[2013 duilib入门简明教程 -- 完整的自绘标题栏(8)]中,可以发现窗口最大化之后有两个问题,     1.最大化按钮的样式 ...

  3. 2013 duilib入门简明教程 -- 部分bug 2 (14)

        上一个教程中提到了ActiveX的Bug,即如果主窗口直接用变量生成,则关闭窗口时会产生崩溃            如果用new的方式生成,则不会崩溃,所以给出一个临时的快速解决方案,即主窗口 ...

  4. 2013 duilib入门简明教程 -- 自绘控件 (15)

        在[2013 duilib入门简明教程 -- 复杂控件介绍 (13)]中虽然介绍了界面设计器上的所有控件,但是还有一些控件并没有被放到界面设计器上,还有一些常用控件duilib并没有提供(比如 ...

  5. 2013 duilib入门简明教程 -- 事件处理和消息响应 (17)

        界面的显示方面就都讲完啦,下面来介绍下控件的响应.     前面的教程只讲了按钮和Tab的响应,即在Notify函数里处理.其实duilib还提供了另外一种响应的方法,即消息映射DUI_BEG ...

  6. 2013 duilib入门简明教程 -- FAQ (19)

        虽然前面的教程几乎把所有的知识点都罗列了,但是有很多问题经常在群里出现,所以这里再次整理一下.     需要注意的是,在下面的问题中,除了加上XML属性外,主窗口必须继承自WindowImpl ...

  7. Mac安装Windows 10的简明教程

    每次在Mac上安装Windows都是一件非常痛苦的事情,曾经为了装Win8把整台Mac的硬盘数据都弄丢了,最后通过龟速系统恢复模式恢复了MacOSX(50M电信光纤下载了3天才把系统下载完),相信和我 ...

  8. Docker简明教程

    Docker简明教程 [编者的话]使用Docker来写代码更高效并能有效提升自己的技能.Docker能打包你的开发环境,消除包的依赖冲突,并通过集装箱式的应用来减少开发时间和学习时间. Docker作 ...

  9. 2013 duilib入门简明教程 -- 总结 (20)

        duilib的入门系列就到尾声了,再次提醒下,Alberl用的duilib版本是SVN上第个版本,时间是2013.08.15~       这里给出Alberl最后汇总的一个工程,戳我下载,效 ...

  10. plain framework 1 参考手册 入门指引之 简明教程

    简明教程 简单的例子 实现代码 简单的例子 如果你已经下载好整个框架的源码,那么你可以在这里找到应用的例子: plainframework/applications/pf_simple 如果你在win ...

随机推荐

  1. appium环境搭建python

    python appium环境搭建   appium是什么? 1,appium是开源的移动端自动化测试框架:2,appium可以测试原生的.混合的.以及移动端的web项目:3,appium可以测试io ...

  2. Mybatis开发中的常用Maven配置

    Mybatis导入Maven配置 <!-- MyBatis导入 --> <dependency> <groupId>org.mybatis</groupId& ...

  3. FastJson不成想还有个版本2啊:序列化大字符串报错

    背景 发现陷入了一个怪圈,写文章的话,感觉只有大bug或比较值得写的内容才会写,每次一写就是几千字,争取写得透彻一些,但这样,我也挺费时间,读者也未必有这么多时间看. 我想着,日常遇到的小bug.平时 ...

  4. 详谈 springboot整合shiro

    背景: 上文学习了shrio 基本概念后,本章将进一步的落地实践学习,在springboot中如何去整合shrio,整个过程步骤有个清晰的了解. 利用Shiro进行登录认证主要步骤: 1. 添加依赖: ...

  5. API接口的对接流程和注意事项

    ​ API接口的对接流程和注意事项 随着互联网技术的发展和数字化时代的到来,API接口已经成为应用程序之间进行数据交换和通信的重要方式.API即应用程序接口,是一种定义.调用和交互的规范,使得不同应用 ...

  6. CodeForces 1367F2 Flying Sort (Hard Version)

    题意 给一个长度为\(n\)的数组,你可以有两种操作 将某一个数放置在数组开头 将某一个数放置在数组结尾 问最小操作多少次可以得到一个非递减数列 (比\(F1\)难在\(n\)变大,且数组中元素可以有 ...

  7. git status详解

    git status详解 在使用Git进行版本控制时,git status是一个非常有用的命令,用于查看当前代码仓库的状态.它可以告诉你哪些文件已更改.添加或删除,以及是否有未提交的更改等.本篇博客文 ...

  8. 简单聊一聊SpringBoot的约定优于配置

    Spring Boot的约定优于配置 对于今天聊的SpringBoot的约定优于配置,我打算从三个方面去展开: 1.什么是约定优于配置 1> 约定优于配置是一种软件设计的范式,其核心思想:使用一 ...

  9. python入门基础(14)--类的属性、成员方法、静态方法以及继承、重载

    上一篇提到过类的属性,但没有详细介绍,本篇详细介绍一下类的属性 一 .类的属性 方法是用来操作数据的,而属性则是建模必不的内容,而且操作的数据,大多数是属性,比如游戏中的某个boss类,它的生命值就是 ...

  10. Vue element-ui 动态生成自定义table表头实现数据渲染

    需求:1)表头的数据是动态的,有可能字段值很长且很多.解决方案自定义动态表头,字段长使用文字提示[el-tooltip组件]: 2)需要对表格data中的数据值进行枚举转成中文值,且显示不同的颜色. ...