简介

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. loader的三种配置方式

    在这篇 webpack处理css资源 文章中使用几个常用的loader 来编译 css 代码. 但其实 loader 的配置方式不止一种,一起来看看其它方式~ 在 webpack.config.js ...

  2. [golang]使用logrus自定义日志模块

    简介 logrus是一个第三方日志库,性能虽不如zap和zerolog,但方便易用灵活.logrus完全兼容标准的log库,还支持文本.JSON两种日志输出格式. 特点 相较于标准库,logrus有更 ...

  3. Oracle内存管理方式介绍(转载)

    "Oracle内存管理可分为两大类,自动内存管理和手动内存管理.其中手动内存管理又可分为自动共享内存管理,手动共享内存管理,自动PGA内存管理以及手动PGA内存管理.本文会简单的介绍不同的内 ...

  4. AT_agc064_a题解

    题面 题目大意 给定一个正整数 \(N\),要求构造一个序列.对于每一个在 \(1\) 到 \(N\) 之间的整数 \(i\),序列中包含了 \(i\) 个,并且将该序列首尾相接拼成环后,相邻两项之差 ...

  5. LeetCode买卖股票之一:基本套路(122)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<LeetCode买卖股票>系列 在L ...

  6. Linux服务器搭建环境复盘

    Linux服务器搭建环境复盘 Linux服务器上是没有开发环境的,需要自己配置,在获得了服务器账号后,通过WinSCP登录可以传文件. 下载anaconda 官网下载Anaconda Linux版本 ...

  7. 在 Net7.0 环境下使用 RestSharp 发送 Http(FromBody和FromForm)请求

    一.简介 最近,在做一个数据传输的服务,我在一个Worker Service里面需要访问 WebAPI 接口,并传输数据,也可以提交数据.由于第一次使用 RestSharp 发送请求,也遇到了很多问题 ...

  8. WPF中以MVVM方式,实现RTSP视频播放

    前言视频播放在上位机开发中经常会遇到,基本上是两种常见的解决方案 1.采用厂家提供的sdk和前端控件进行展示,常见的海康/大华都提供了相关sdk及文档 2.开启相机onvif协议,捅过rtsp视频流进 ...

  9. 使用 OpenTelemetry 构建 .NET 应用可观测性(3):.NET SDK 概览

    目录 前言 概览 opentelemetry-dotnet opentelemetry-dotnet-contrib opentelemetry-dotnet-instrumentation SDK ...

  10. 文心一言 VS 讯飞星火 VS chatgpt (104)-- 算法导论10.1 2题

    二.用go语言,说明如何在一个数组 A[1..n]中实现两个栈,使得当两个栈的元素个数之和不为 n 时,两者都不会发生上溢.要求 PUSH 和 POP 操作的运行时间为 O(1). 文心一言: 在这个 ...