文档章节

EventBus教程

k
 kim366
发布于 2016/05/13 19:17
字数 2292
阅读 10
收藏 0
点赞 2
评论 0

        在上一篇文章中,已经稍微了解了下EventBus和一些基本概念,包括如何在项目中添加EventBus支持。下面就深入学习如何使用。

 

一般使用和API

依据上篇中的三个步骤,并进行一些扩展。

1: 定义 EventBus

Events are POJO (plain old Java object) without any specific requirements.

事件就是一个包含特定要求的原始Java对象

publicclassMessageEvent {
    publicfinal String message;

    publicMessageEvent(String message) {
        this.message = message;
    }
}

2: 准备订阅者

订阅者实现事件处理方法onEvent,当一个事件被接收时会调用这个方法。 这些订阅者需要在总线中注册和解注册他们自己。

@Override
    publicvoid onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

    @Override
    publicvoid onStop() {
        EventBus.getDefault().unregister(this);
        super.onStop();
    }

    // This method will be called when a MessageEvent is posted 当一个MessageEvent被传递的时候,这个方法会被调用publicvoid onEvent(MessageEvent event){
        Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
    }

    // This method will be called when a SomeOtherEvent is posted 当一个SomeOtherEvent被传递的时候,这个方法会被调用publicvoid onEvent(SomeOtherEvent event){
        doSomethingWith(event);
    }

3: 提交事件

从你代码的任意地方发布这个事件, 所有匹配这个事件的订阅者会接收到它。

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


传递线程和ThreadModes

EventBus可以帮助你处理线程问题: 事件可以在与提交线程不同的线程中被提交。 

一个常用的场景是处理UI改变。在Android中,UI 改变必须在UI线程中进行。另外,网络请求以及其他的耗时任务都不应该在主线程中操作。 EventBus可以帮助你处理这些事情,并与主线程同步(而不必使用AsynTask深入处理线程过渡等)。


在EventBus中,你可以使用ThreadMode定义线程,这个线程可以调用事件处理方法onEvent。

  • 提交线程:订阅者默认会在与提交事件相同的线程中被调用。事件传递意味着最小的开销,因为它完全避免了线程切换。所以,对于简单的短时任务,这是一种被推荐的模式,对主线程不会有什么要求。使用这种模式的事件处理器应该快速返回以避免阻塞提交线程, 因为这个线程可能是主线程。例如:
    // Called in the same thread (default)
    public void onEvent(MessageEvent event) {
        log(event.message);
    }
  • 主线程:订阅者会在Android的主线程中被调用(UI线程)。如果事件发布线程是主线程,那么,事件处理器方法会被直接调用。使用这种模式的事件处理器必须迅速返回以避免阻塞主线程。例如:
    // Called in Android UI's main thread
    public void onEventMainThread(MessageEvent event) {
        textField.setText(event.message);
    }
  • 后台线程:订阅者会在后台线程中被调用。如果提交线程不是主线程,那么事件处理方法会在提交线程中被直接调用。如果发布线程是主线程,则事件总线会使用一个能够传递所有事件的单独后台线程。使用这种模式的事件处理器应该快速返回,以免阻塞后台线程。
    // Called in the background thread
    public void onEventBackgroundThread(MessageEvent event){
        saveToDisk(event.message);
    }
  • 同步:事件处理器方法在独立的线程中被调用。这个线程通常独立于提交线程和主线程。使用这种模式,发布事件始终不会等待事件处理器方法。如果他们的执行过程比较耗时的话,事件处理器方法应该使用这种模式。避免同时触发大量的耗时的异步处理方法以限制并发线程。 EventBus使用一个线程池从完成的异步事件处理通知中高效地复用线程。
    // Called in a separate thread
    public void onEventAsync(MessageEvent event){
        backend.send(event.message);
    }

注:EventBus根据名字在合适的线程中调用onEvent方法(onEvent, onEventA)


订阅者优先级和有序事件传递

可以在注册订阅者的时候,提供一个优先级改变事件传递的顺序。

    int priority =1;
    EventBus.getDefault().register(this, priority);

在同一个传递线程中(ThreadMode),优先级高的订阅者会在优先级低的订阅者之前收到事件,默认优先级为0.

注意:优先级不会影响具有不同ThreadModes的订阅者之间的传递顺序


使用EventBusBuilder配置EventBus

EventBus2.3  添加了EventBusBuilder用于配置不同的EventBus切面。例如, 下面是创建一个在发布的事件没有订阅者的情况下保持静默的EventBus的过程。 

EventBus eventBus = EventBus.builder().logNoSubscriberMessages(false).sendNoSubscriberEvent(false).build();

另一个是当订阅者执行失败时抛出异常的例子。注意:  EventBus捕获到从onEvent方法中抛出的异常,并发送一个SubscirberExceptionEvent,不过不一定要处理。

EventBus eventBus = EventBus.builder().throwSubscriberException(true).build();

可以查看EventBusBuilder类和其文档获取可能的配置。


配置默认的EventBus实例

使用EventBus.getDefualt()是一种获取共享EventBus实例的简单方式。EventBusBuilder也允许使用installDefaultEventBus()配置这个默认的实例。

例如,可以通过配置默认的事件总线方法实例重新抛出onEvent方法中发生的异常。但是, 这个情况只使用于DEBUG构建中,因为这可能导致app奔溃。

注意:只能在默认的事件总线第一次被使用之前进行一次。确保在你的应用中的持续行为。在使用之前,你的Appllication类是配置默认事件总线的好地方。


取消事件传递

可以从订阅者的事件处理方法中通过cancelEventDelivery(Object event)取消事件传递过程. 这样所有的进阶事件传递都会被取消,后续订阅者不会再收到事件。
事件通常是被优先级高的订阅者取消。对运行于提交线程 ThreadMode.PostThread .的事件处理方法来说,取消过程是比较严格的。

粘性事件

有些事件在提交之后携带着有益的信息。例如,可能是一个表明一些出初始化工作完成的事件信号。 或者,如果你有一些传感器和位置信息,并且你希望持有为最近的值。 这样,你可以使用粘性事件,而不是实现自己的缓存。事件总线在内存中保持着特定类型的最终粘性事件。这些粘性事件可以被传递给订阅者或者用于明确查询。所以,不需要任何的特殊逻辑来考虑已经可以获得的数据。

粘性事件在一个特定事件之前发布。

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

此后,一个新的Act启动,使用registerSticky注册期间,就会立即获得之前发布的粘性事件。

@Override
    publicvoid onStart() {
        super.onStart();
        EventBus.getDefault().registerSticky(this);
    }

    publicvoid onEventMainThread(MessageEvent event) {
        textField.setText(event.message);
    }

    @Override
    publicvoid onStop() {
        EventBus.getDefault().unregister(this);
        super.onStop();
    }

你也可以通过下面的方式,获得特定类型的最后一个粘性事件

       EventBus.getDefault().getStickyEvent(Class<?>  eventType)
也可以通过removeStickyEvent()方法移除之前提交的粘性事件。 这个方法具有一个固定的事件对象或者是一个事件类。 像这样,可以创建可以消费的事件。 记住,一个事件类型,只有最后的事件会被保持。


混淆配置

混淆器,会混淆方法名,不过,onEvent()方法不会被重命名,因为他们是通过反射获得的。在混淆器中使用下面的代码。

-keepclassmembers class ** {
    public void onEvent*(**);
}

# Only required if you use AsyncExecutor
-keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}


异步执行器

申明:AsyncExecutor是一个非核心的实体类。这个类可以通过后台错误处理线程省下一些代码,但不是EventBus的核心。

AsyncExecutor就像线程池,只不过具有失败处理能力。如果失败会抛出异常,这个异常被包装在一个事件内部中,并自动被AsyncExecutor抛出。

通常情况下,可以使用AsyncExecutor.create()创建一个实例,并在Application作用域内持有。如果要执行一些事情,可以实现RunnableEx接口,并将其传递到AsyncExecutor的执行方法中。与Runnable不同,RunnableEx可能抛出异常。

如果RunnableEx的实现抛出异常,这个异常会被捕获到,并包装进一个ThrowableFailureEvent对象中,发布出来。


Code example for execution:

AsyncExecutor.create().execute(
  new RunnableEx {
    publicvoid run throws LoginException {
      remote.login();
      EventBus.getDefault().postSticky(new LoggedInEvent());
      // No need to catch Exception
    }
  }
}

Code example for the receiving part:

publicvoid onEventMainThread(LoggedInEvent event) {
  // Change some UI
}

publicvoid onEventMainThread(ThrowableFailureEvent event) {
  // Show error in UI
}


AsyncExecutor 构建器

如果你想自定义AsyncExecutor实例,可以调用静态方法AsyncExecutor.build()方法。这样可以返回一个允许你自定义EventBus实例,线程池,以及失败事件类的构造器。
另一个自定义选项是执行作用域,这个选项会给出失败事件的上下文信息。例如,一个失败的事件可能只与一个特定的Activity实例或者类有关。如果你自定义失败事件类实现HasExecutionScope接口,则AsyncExecutor会自动设置执行作用域。比如,订阅者可以在执行作用域内查询失败事件并与之交互。


与Otto比较

Check the COMPARISON.md

© 著作权归作者所有

共有 人打赏支持
k
粉丝 1
博文 129
码字总数 0
作品 0
朝阳
Android之撸一个类似EventBus的轮子

用过eventBus的人都知道,在组件及时通讯中,使用非常方便。 一般我们是这样做的:总结为三部曲: 这就是EventBus的强大之处,用过的人都说好,哈哈哈哈!!!! 上图描述吧。有图有真相 Cr...

还有de小星 ⋅ 05/25 ⋅ 0

RxJava实现的EventBus-RxBus

使用RxJava2实现RxBus 当我们使用RxJava2实现EventBus模式时,我们称其为RxBus. 注意:这仅作为一个例子。 那么,就让我们来看看如何使用RxJava2实现RxBus吧 首先,你得了解RxJava中有关sub...

塞上牧羊空许约 ⋅ 05/12 ⋅ 0

【死磕Sharding-jdbc】—–路由&执行

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/09efada2d086 继续以模块中的为基础,剖析分库分表简单查询SQL实现--,即如何执行简单的查询SQL,接下来的分析以执行SQL语句为例...

飞哥-Javaer ⋅ 05/03 ⋅ 0

gis-luq/RuntimeViewer

RuntimeViewer —— 基于ArcGIS Runtime 100.x开发的移动应用程序框架 组件式开发框架,兼容手机、平板多种设备。 平板模式 手机模式 使用说明 项目采用插件化结构设计,文件夹架构说明如下 ...

gis-luq ⋅ 05/11 ⋅ 0

Android 计步器应用 - healthgo

healthgo a android pedometer app (安卓计步器) Support Android 4.1- 7.0 Thanks Project/People desc other Realm a mobile database 使用了这个数据库 EventBus a publish/subscribe eve......

五十风 ⋅ 04/13 ⋅ 0

基于 MVP 架构使用Android通用开发框架快速开发微博项目实战

课程目标: 基于 MVP 架构使用Android通用开发框架快速开发微博项目实战 适应人群: 适合大学生和初中级android开发工程师,可以系统化的微博类APP的开发,系统化掌握商业化项目的开发。* 不...

13122542396 ⋅ 05/25 ⋅ 0

阿里ARouter路由实现Android模块化开发

概述 从 2016 年开始,模块化在 Android 社区越来越多的被提及。随着移动平台的不断发展,移动平台上的软件慢慢走向复杂化,体积也变得臃肿庞大,为了降低大型软件复杂性和耦合度,同时也为了...

code_xzh ⋅ 04/24 ⋅ 0

Android官方架构组件之LiveData + ViewModel + Room 源码分析一

简单使用案例: MainActivity: MessageViewModel: 其中viewModel.getMessageObserver().observe(this, new Observer() ) 中的this即SupportActivity :LifecycleOwner SupportActivity im......

编程之乐 ⋅ 05/23 ⋅ 0

Android 开发者应该知道的 Kotlin 技巧

今年的 Google I/O 大会上,Google 是这样评价 Kotlin:在过去一年里,有35%的专业 Android 开发者在使用 Kotlin,其中95%的开发者都对 Kotlin 非常满意。虽然 Kotlin 正处于发展的初始阶段,...

码云Gitee ⋅ 05/28 ⋅ 0

Step-by-step,打造属于自己的 Vue SSR

编者按:本文由 玩弄心里的鬼 发表于掘金,已授权奇舞周刊转载 笔者最近在和小伙伴对vue项目进行ssr的升级,本文笔者将根据一个简单拿vue cli构建的客户端渲染的demo一步一步的教大家打造自己...

奇舞周刊 ⋅ 04/17 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

LVM

LVM: 硬盘划分分区成物理卷->物理卷组成卷组->卷组划分逻辑分区。 1.磁盘分区: fdisk /dev/sdb 划分几个主分区 输入t更改每个分区类型为8e(LVM) 使用partprobe生成分区的文件:如/dev/sd...

ZHENG-JY ⋅ 38分钟前 ⋅ 0

彻底删除Microsoft Office的方法

参照此链接彻底删除Office https://support.office.com/zh-cn/article/%e4%bb%8e-pc-%e5%8d%b8%e8%bd%bd-office-9dd49b83-264a-477a-8fcc-2fdf5dbf61d8?ui=zh-CN&rs=zh-CN&ad=CN......

Kampfer ⋅ 53分钟前 ⋅ 0

大盘与个股之间关系

大盘走多:积极出手 顺势加码 大盘走空: 少量出手 退场观望 大盘做头:逆势减码 少量操作 大盘做底 : 小量建仓 小量试单

guozenhua ⋅ 55分钟前 ⋅ 0

Day16 LVM(逻辑卷管理)与磁盘故障小案例

lvm详解 简述 LVM的产生是因为传统的分区一旦分区好后就无法在线扩充空间,也存在一些工具能实现在线扩充空间但是还是会面临数据损坏的风险;传统的分区当分区空间不足时,一般的解决办法是再...

杉下 ⋅ 今天 ⋅ 0

rsync实现多台linux服务器的文件同步

一、首先安装rsync,怎样安装都行,rpm,yum,还是你用源码安装都可以。因为我用的是阿里云的ESC,yum install rsync就ok了。 二、配置rsync服务 1.先建立个同步数据的帐号 123 groupadd r...

在下头真的很硬 ⋅ 今天 ⋅ 0

前端基础(三):函数

字数:1685 阅读时间:5分钟 函数定义 在最新的ES规范中,声明函数有4中方法: -函数声明 -函数表达式 -构造函数Function -生成器函数 1.函数声明 语法: function name([param[, param2 [....

老司机带你撸代码 ⋅ 今天 ⋅ 0

Java虚拟机的Heap监狱

在Java虚拟机中,我是一个位高权重的大管家,他们都很怕我,尤其是那些Java 对象,我把他们圈到一个叫做Heap的“监狱”里,严格管理,生杀大权尽在掌握。 中国人把Stack翻译成“栈”,把Hea...

java高级架构牛人 ⋅ 今天 ⋅ 0

Spring MVC基本概念

只写Controller

颖伙虫 ⋅ 今天 ⋅ 0

微软重金收购GitHub的背后逻辑原来是这样的

全球最大的开发者社区GitHub网站花落谁家的问题已经敲定,微软最终以75亿美元迎娶了这位在外界看来无比“神秘”的小家碧玉。尽管此事已过去一些时日,但整个开发者世界,包括全球各地的开源社...

linux-tao ⋅ 今天 ⋅ 0

磁盘管理—逻辑卷lvm

4.10-4.12 lvm 操作流程: 磁盘分区-->创建物理卷-->划分为卷组-->划分成逻辑卷-->格式化、挂载-->扩容。 磁盘分区 注: 创建分区时需要更改其文件类型为lvm(代码8e) 分区 3 已设置为 Linu...

弓正 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部