一、         EventBus简介

1.1EventBus

EventBus 是一个 Android 事件发布/订阅框架,通过解耦发布者和订阅者简化Android 事件传递,这里的事件可以理解为消息,本文中统一称为事件。事件传递既可用于 Android 四大组件间通讯,也可以用户异步线程和主线程间通讯等等。

传统的事件传递方式包括:Intent、Handler、BroadCastReceiver、Interface 回调,相比之下 EventBus 的优点是代码简洁,使用简单,并将事件发布和订阅充分解耦。可简化 Activities, Fragments, Threads, Services 等组件间的消息传递,可替代Intent、Handler、BroadCast、接口等传统方案,更快,代码更小,50K 左右的 jar 包,代码更优雅,彻底解耦。

1.2、概念

事件(Event):又可称为消息,本文中统一用事件表示。其实就是一个对象,可以是网络请求返回的字符串,也可以是某个开关状态等等。事件类型(EventType)指事件所属的 Class。

事件分为一般事件和 Sticky 事件,相对于一般事件,Sticky 事件不同之处在于,当事件发布后,再有订阅者开始订阅该类型事件,依然能收到该类型事件最近一个Sticky事件。

订阅者(Subscriber):订阅某种事件类型的对象。当有发布者发布这类事件后,EventBus 会执行订阅者的onEvent 函数,这个函数叫事件响应函数。订阅者通过register 接口订阅某个事件类型,unregister 接口退订。订阅者存在优先级,优先级高的订阅者可以取消事件继续向优先级低的订阅者分发,默认所有订阅者优先级都为0。

发布者(Publisher):发布某事件的对象,通过 post 接口发布事件。

1.3、订阅者、发布者、EventBus 关系图
EventBus 负责存储订阅者、事件相关信息,订阅者和发布者都只和
EventBus 关联。

事件响应流程

订阅者首先调用 EventBus的 register 接口订阅某种类型的事件,当发布者通过 post 接口发布该类型的事件时,EventBus 执行调用者的事件响应函数。

二、        
EventBus优势

2.1、对比Java监听器接口(Listener Interfaces

在Java中,特别是Android,一个常用的模式就是使用“监听器(Listeners)”接口。在此模式中,一个实现了监听器接口的类必须将自身注册到它想要监听的类中去。这就意味着监听与被监听之间属于强关联关系。这种关系就使得单元测试很难进行开展。

2.2、对比本地广播管理器(LocalBroadcastManager

另一项技术就是在组件间通过本地广播管理器(LocalBroadcastManager)进行消息的发送与监听。虽然这对于解耦有很好的帮助,但它的API不如EventBus那样简洁。此外,如果你不注意保持Intent extras类型的一致,它还可能引发潜在的运行时/类型检测错误。

使用EventBus不仅使代码变得清晰,而且增强了类型安全(type-safe)。当用Intent传递数据时,在编译时并不能检查出所设的extra类型与收到时的类型一致。所以一个很常见的错误便是你或者你团队中的其他人改变了Intent所传递的数据,但忘记了对全部的接收器(receiver)进行更新。这种错误在编译时是无法被发现的,只有在运行时才会发现问题。

而使用EventBus所传递的消息则是通过你所定义的Event类。由于接收者方法是直接与这些类实例打交道,所以所有的数据均可以进行类型检查,这样任何由于类型不一致所导致的错误都可以在编译时刻被发现。

另外就是你的Event类可以定义成任何类型。通常会为了表示事件而显式地创建明确命名的类,你也通过EventBus发送/接收任何类。通过这种方法,你就不必受限于那些只能添加到Intent extras中的简单数据类型了。例如,你可以发送一个和ORM模型类实例,并且在接收端直接处理与ORM操作相关的类实例。

三、        
EventBus使用

3.1基本使用

3.2具体案例

3.3 onEvent函数使用解析

前一篇给大家装简单演示了EventBus的onEventMainThread()函数的接收,其实EventBus还有另外有个不同的函数,他们分别是:

1、onEvent
2、onEventMainThread
3、onEventBackgroundThread
4、onEventAsync

这四种订阅函数都是使用onEvent开头的,它们的功能稍有不同,在介绍不同之前先介绍两个概念:告知观察者事件发生时通过EventBus.post函数实现,这个过程叫做事件的发布,观察者被告知事件发生叫做事件的接收,是通过下面的订阅函数实现的。
onEvent:如果使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
onEventMainThread:如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中更新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
onEventBackground:如果使用onEventBackgrond作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
onEventAsync使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync.

3.4 EvetntBus3.0使用解析

注册一般是在 onCreate 和 onStart 里注册,尽量不要在 onResume,可能出现多次注册的情况,比如下面这个异常:

取消注册 要写到 onDestroy 方法里,不要写到 onStop 里,有时会出现异常的哦

EventBus 3 和之前版本的 EventBus 不兼容,这里采用注解的方法来接收事件,四种注解 @Subscrible、@Subscrible(threadMode = ThreadMode.ASYNC)、@Subscribe(threadMode
= ThreadMode.BACKGROUND)、@Subscribe(threadMode = ThreadMode.MAIN)分别对应之前的 onEvent()、onEventAsync()、onEventBackground()、onEventMainThread()。

EventBus 3 采用注解后,方法名没有限制了,参数只有一个,和发送者 post 的参数对应配对,在未声明 threadMode 时,默认的线程模式为 ThreadMode.POSTING,只有在该模式下才可以取消线程。

由于可在任何地方都可以 post 一个事件,那么在不同线程之间传递事件,比如在工作线程传递一个事件更新UI线程中的一个控件,则需要注意 threadMode 的切换。

如果遇到订阅事件无法执行的情况,分析后发现是订阅事件的 Activity 还未执行的原因。找到原因就好办了,这时候就需要用到 postSticky。

四、        
EventBus源码解析

4.1 register

EventBus.getDefault().register(this);
 EventBus.getDefault()其实就是个单例,和我们传统的getInstance一个意思:

使用了双重判断的方式,防止并发的问题,还能极大的提高效率。

register公布给我们使用的有4个:

调用内部类SubscriberMethodFinderfindSubscriberMethods方法,传入了subscriber class,以及methodName,返回一个List<SubscriberMethod>

那么不用说,肯定是去遍历该类内部所有方法,然后根据methodName去匹配,匹配成功的封装成SubscriberMethod,最后返回一个List

继续回到register:

到此,我们register就介绍完了。

你只要记得一件事:扫描了所有的方法,把匹配的方法最终保存在subscriptionsByEventTypeMapkeyeventType valueCopyOnWriteArrayList<Subscription> )中;

eventType是我们方法参数的ClassSubscription中则保存着subscriber,
subscriberMethod
method, threadMode, eventType, priority;包含了执行改方法所需的一切。

4.2 post

到此,我们完整的源码分析就结束了,总结一下:register会把当前类中匹配的方法,存入一个map,而post会根据实参去map查找进行反射调用。分析这么久,一句话就说完了~~

其实不用发布者,订阅者,事件,总线这几个词或许更好理解,以后大家问了EventBus,可以说,就是在一个单例内部维持着一个map对象存储了一堆的方法;post无非就是根据参数去查找方法,进行反射调用。

 

 

EventBus源码分析的更多相关文章

  1. ABP源码分析二十五:EventBus

    IEventData/EventData: 封装了EventData信息,触发event的源对象和时间 IEventBus/EventBus: 定义和实现了了一系列注册,注销和触发事件处理函数的方法. ...

  2. Android 框架学习2:源码分析 EventBus 3.0 如何实现事件总线

    Go beyond yourself rather than beyond others. 上篇文章 深入理解 EventBus 3.0 之使用篇 我们了解了 EventBus 的特性以及如何使用,这 ...

  3. 8.源码分析---从设计模式中看SOFARPC中的EventBus?

    我们在前面分析客户端引用的时候会看到如下这段代码: // 产生开始调用事件 if (EventBus.isEnable(ClientStartInvokeEvent.class)) { EventBu ...

  4. EventBus 使用/架构/源码分析

    EventBus是针对Android优化的发布-订阅事件总线,简化了Android组件间的通信.EventBus以其简单易懂.优雅.开销小等优点而备受欢迎. github 地址:https://git ...

  5. guava eventbus 原理+源码分析

    前言: guava提供的eventbus可以很方便的处理一对多的事件问题, 最近正好使用到了,做个小结,使用的demo网上已经很多了,不再赘述,本文主要是源码分析+使用注意点+新老版本eventbus ...

  6. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  7. ABP源码分析三十六:ABP.Web.Api

    这里的内容和ABP 动态webapi没有关系.除了动态webapi,ABP必然是支持使用传统的webApi.ABP.Web.Api模块中实现了一些同意的基础功能,以方便我们创建和使用asp.net w ...

  8. ABP源码分析四十七:ABP中的异常处理

    ABP 中异常处理的思路是很清晰的.一共五种类型的异常类. AbpInitializationException用于封装ABP初始化过程中出现的异常,只要抛出AbpInitializationExce ...

  9. 【Android】EventBus 源码解析

    EventBus 源码解析 本文为 Android 开源项目实现原理解析 中 EventBus 部分项目地址:EventBus,分析的版本:ccc2771,Demo 地址:EventBus Demo分 ...

随机推荐

  1. (转,记录用)jQuery页面加载初始化的3种方法

    jQuery 页面加载初始化的方法有3种 ,页面在加载的时候都会执行脚本,应该没什么区别,主要看习惯吧,本人觉得第二种方法最好,比较简洁. 第一种: $(document).ready(functio ...

  2. centos7 docker安装和使用_入门教程

    说明:本文也是参考互联网上的文章写的,感谢相关作者的贡献. 操作系统 64位CentOS Linux release 7.2.1511 (Core) 配置好IP:192.168.1.160 修改yum ...

  3. 字符串转码【String.getBytes()和new String()】

    在Java中,String.getBytes(String decode)方法会根据指定的decode编码返回某字符串在该编码下的byte数组表示,如 byte[] b_gbk = "中&q ...

  4. 【Go入门教程4】变量(var),常量(const),内置基础类型(Boolean、数值 byte,int,rune、字符串、错误类型),分组,iota枚举,array(数值),slice(切片),map(字典),make/new操作,零值

    这小节我们将要介绍如何定义变量.常量.Go 内置类型以及 Go 程序设计中的一些技巧. 定义变量 Go 语言里面定义变量有多种方式. 使用 var 关键字是 Go 最基本的定义变量方式,与 C 语言不 ...

  5. Netdata----Linux 性能实时监测工具

    https://my-netdata.io/ https://github.com/firehol/netdata/wiki http://soluck.iteye.com/blog/2291618

  6. WCF实现将服务器端的错误信息返回到客户端

    转载:http://www.cnblogs.com/zeroone/articles/2299001.html http://www.it165.net/pro/html/201403/11033.h ...

  7. [转]关于适配iphone5,Invalid Launch Image的退信

    关于适配iphone5,Invalid Launch Image的退信 本人xcode 4.3,所开发客户端新版本准备提交,应用中做了关于iphone5的适配,然后打包提交.在提交审核的时候被拒,收到 ...

  8. 防火墙 0x80070422

    1.无法打开操作中心-安全服务,解决方法:控制面板->管理工具->服务,找到Security Center 服务,双击打开,查看启动类型是否设置成禁用,是的话更改成自动或者延迟启动,之后就 ...

  9. Extjs DateField onchange

    1 开发思路: 在日期值变化的事件中获得选择后的日期值,传给后台,然后从后台加载相应的数据 2 问题:在查看extjs2.2 的api的官方说明文档,文档对datefield组件的change事件说明 ...

  10. kafka深入研究(六)

    Kafka Producer端封装自定义消息 Kafka.network包源码解读 Kafka Consumer端的一些解惑 Kafka producer使用注意 kafka0.8的一些变动,先收藏, ...