简介

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. DateTime和DateTimeOffset是同胞兄弟吗?

    小编在日常开发中,用得最多的时间类型就是DateTime,直到一次偶然的邂逅,让小编遇见了DateTimeOffset.当时小编也是一脸迷茫,因为在小编的C#编程字典里就没出现过DateTimeOff ...

  2. redis的一些简单操作(针对key)

    redis默认16个数据,默认使用0号 select为切换数据库的关键字 select 1  切换数据库 设置值 set k1 lucy       key为 k1  value 为 lucy 查看全 ...

  3. APubPlat 一款Devops自动化部署、持续集成、堡垒机开源项目、友好的Web Terminal

    嗨.很高心你能进入这里,我是zane,  在这里给你介绍一款完整的Devops自动化部署工具 APubPlat - 一款完整的Devops自动化部署.持续集成.堡垒机.并且友好的Web Termina ...

  4. nginx配置源IP访问控制

    通过nginx的ngx_http_access_module模块,可实现对客户端的源IP地址进行允许或拒绝访问控制.该模块默认已编译. 允许访问指令 名称 允许访问指令 指令 allow 作用域 ht ...

  5. go-zero 是如何做路由管理的?

    原文链接: go-zero 是如何做路由管理的? go-zero 是一个微服务框架,包含了 web 和 rpc 两大部分. 而对于 web 框架来说,路由管理是必不可少的一部分,那么本文就来探讨一下 ...

  6. 4.2 C++ Boost 内存池管理库

    Boost 库是一个由C/C++语言的开发者创建并更新维护的开源类库,其提供了许多功能强大的程序库和工具,用于开发高质量.可移植.高效的C应用程序.Boost库可以作为标准C库的后备,通常被称为准标准 ...

  7. 优化Redis缓存淘汰机制解决性能测试中报错率逐渐攀升问题

    在某个查询场景的性能测试过程中,遇到了一个问题:测试过程中报错率逐渐攀升.进一步检查后发现,在查询业务所在应用的后台日志和平台应用的后台日志中,都出现了用户登录相关的报错信息.经过排查分析,发现了问题 ...

  8. Code Llama:Llama 2 学会写代码了!

    引言 Code Llama 是为代码类任务而生的一组最先进的.开放的 Llama 2 模型,我们很高兴能将其集成入 Hugging Face 生态系统!Code Llama 使用与 Llama 2 相 ...

  9. Python 搭建 FastAPI 项目

    一般网上的文章都是以脚本的方式写Demor的,没找到自己想要的那种项目结构型的示例(类似Java SpringBoot 创建 Model,通过 pom 进行关联配置的那种) 看了一些源码,再结合自己的 ...

  10. PowerShell收集信息及绕过PowerShell权限

    PowerShell脚本的4种执行权限: Restricted:默认设置,不允许任何script运行 AllSigned:只能运行经过数字证书签名的script RemoteSigned:本地脚本不做 ...