【Android开发】greenrobot三大开源利器详解(一)——EventBus

Published on in JAVA with 0 views and 0 comments

一、greenrobot介绍
greenrobot相关信息较少,可以确信是一个开源组织。官网:http://greenrobot.org/。
greenrobot主要开发并维护了3个Android开源库,即greenDAO、EventBus、和Essentials。三个开源库都可以在GitHub上进行下载。本节讲解其中最著名的EventBus。

二、EventBus概述
EventBus的官方解释是:

“EventBus is a central publish/subscribe event system for Android. Events are posted (post(Object)) to the bus, which delivers it to subscribers that have a matching handler method for the event type. To receive events, subscribers must register themselves to the bus using register(Object). Once registered, subscribers receive events until unregister(Object) is called. Event handling methods must be annotated by Subscribe, must be public, return nothing (void), and have exactly one parameter (the event).”

从中可以看出,EventBus是一个专门为Android优化的“发布/订阅”模式的事件总线(原文:EventBus is a publish/subscribe event bus optimized for Android)。。事件被发布到事件总线(bus),然后事件总线将事件发送给符合条件的订阅者,这里的符合条件是通过订阅者重写的处理方法的方法签名来判断的。
image.png

这里根据EventBus在GitHub主页(https://github.com/greenrobot/EventBus)上的介绍进行翻译,EventBus的特性包括:
 简化了组件间的通讯
 分离了事件的发送者和接受者;
 在Activity、Fragment和线程中表现良好;
 避免了复杂的和易错的依赖关系和声明周期问题;
 使得代码更简洁;
 更快;
 更小(约50k的jar包)
 实际上超过1亿的app证明了它的性能;
 有高级属性,例如发布线程、订阅属性等。

三、相关资料
 eventbus-3.0.0-beta1.jar:eventbus 3.0的类库,放入工程中的libs文件夹即可使用;
 eventbus-3.0.0-beta1-javadoc:eventbus3.0的离线API
 eventbus-3.0.0-beta1-sources:eventbus3.0的源码
 源码地址:https://github.com/greenrobot/EventBus
Github上的源码下载后由于诸多依赖关系,本人尝试多次后仍未能通过编译。所以,推荐使用jar包的方式进行使用。
资料下载:eventbus相关jar包

四、 EventBus使用
4.1 API解析
(1)ThreadMode
ThreadMode是enum类型,用在事件处理函数的方法注解中,标示事件处理函数是那种类型。每一个订阅者都通过事件处理函数来接收和处理事件,而事件处理函数有4种模式:
 Async
这种模式下,订阅者的事件处理函数运行在新开启的线程中,而不论发布者是UI线程还是子线程。
 BackgroundThread
这种模式与Async的区别在于,如果发布者不是UI线程,那么订阅者的事件处理函数直接在发布者的线程中运行,不必新开线程。
 MainThread
在UI线程中运行事件处理函数。
 PostThread
在与发布者相同的线程中运行.
(2)EventBus
有3种初始化方式。
 单例模式的默认配置

EventBus eventBus =EventBus.getDefault();//本质是调用了new EventBus()

 new方式

EventBus eventBus =new EventBus();//默认配置

 建造者模式的自定义配置

EventBusBuilder busBuilder=EventBus.builder();//生成建造者
busBuilder.eventInheritance(false);//默认是true,支持事件继承的。
busBuilder.logNoSubscriberMessages(false);//默认是true,没有订阅者时打印相关log
……
EventBus eventBus=busBuilder.build();

这里要注意的是,通过单例模式生成默认eventBus具有线程的全局单例特性。实践中,通过new或者建造者模式生成的eventBus可以放在Application中初始化。
EventBus的常用方法有:

 post(java.lang.Object event):发布事件。
 postSticky(java.lang.Object event):发布sticky事件
 register(java.lang.Object subscriber):注册订阅者
 removeAllStickyEvents():清除所有sticky事件
 removeStickyEvent(java.lang.Class eventType):清除某种类型的所有sticky事件
 removeStickyEvent(java.lang.Object event):清除某个sticky事件
 unregister(java.lang.Object subscriber):解除订阅者

(3)EventBusBuilder
用于配置EventBus的属性。

4.2 基本用法
EventBus使用的步骤是:声明事件→注册订阅者→发布事件。最简单的用法是用默认的单例模式。
(1)第一步,声明事件:
事件即定义用于传递的某种消息的类。这里定义了3个简单的类FirstEvent、SecondEvent、ThirdEvent,三者形式相同。

/**
 * Created by CaoYanfeng on 2016/3/15.
 */
public class FirstEvent {

    private String mMsg;
    public FirstEvent(String msg) {
        // TODO Auto-generated constructor stub
        mMsg = msg;
    }
    public String getMsg(){
        return mMsg;
    }
}

(2)注册订阅者
例如,在Activity的onCreat()中进行注册:

EventBus.getDefault().register(this);
1
注意,订阅者必须实现至少一个事件处理函数,否则会报错。在Activity中实现4种类型的事件处理函数:

    /**
    必须使用标记符。这表明要在UI线程中处理
    */
    @Subscribe(threadMode = ThreadMode.MainThread)
    public void onEventMainThread(FirstEvent event) {
        String msg = "onEventMainThread收到了消息:" + event.getMsg();
        Log.d("harvic", msg);
    }
/**
    必须使用标记符。这表明要在与发布线程相同的线程中处理
    */
@Subscribe(threadMode = ThreadMode.PostThread)
    public void onEvent(ThirdEvent event) {
        Log.d("harvic", "OnEvent收到了消息:" + event.getMsg());
    }
/**
    必须使用标记符。这表明如果是在UI线程中发布,则在新线程中运行
    */
    @Subscribe(threadMode = ThreadMode.BackgroundThread)
    public void onEventBackgroundThread(SecondEvent event){
        Log.d("harvic", "onEventBackground收到了消息:" + event.getMsg());
}
/**
    必须使用标记符。在新线程中运行
    */
    @Subscribe(threadMode = ThreadMode.Async)
    public void onEventAsync(SecondEvent event){
        Log.d("harvic", "onEventAsync收到了消息:" + event.getMsg());
    }

(3)发布事件
发布事件可以在UI线程、子线程。例如:

EventBus.getDefault().post(new FirstEvent("FirstEvent btn clicked"));

4.3 Sticky事件
“声明事件→注册订阅者→发布事件”的顺序限制了EventBus的使用范围。例如,Activity1跳转到Activity2的过程中,需要将事件从Activity1发布,而需要在Activity2中进行订阅。由于跳转前Activity2并没有初始化,不能注册为订阅者。
将事件发布为Sticky事件,本质上是将事件保存到了EventBus中的Map数据结构。查看EventBus源码,可以印证:
private final Map

4.4 事件的继承性
通过默认方式生产的EventBus是默认配置,这些配置保证了如果发布的是子类对象,订阅的是父类对象,仍然可以接收到目标事件,因为子类向上进行类型转换是不会出问题的(反之则不一定)。如果要阻止这种情况,即保证发布子类对象,而订阅父类对象时不必接收目标事件,那就不能用默认配置,而需要用构造者模式。

EventBusBuilder busBuilder=EventBus.builder();//生成建造者
busBuilder.eventInheritance(false);//默认是true,这里设置为false。
EventBus eventBus=busBuilder.build();

五、 EventBus源码分析
EventBus本质上是观察者模式。源码分析见:android 开源工具 EventBus的使用和源码分析。

六、 Demo说明
这里我写了个Demo,下载地址为:EventBusDemo。
工程EventBusDemo实现两个Activity跳转。逻辑如下:
 FirstEvent、SecondEvent、ThirdEvent、StickyEvent、ThirdEventChild分别是事件类,ThirdEventChild继承自ThirdEvent;App中采用建造者模式生成了EventBus,并阻止了继承模式;

 MainActiy将自己作为订阅者注册到默认的EventBus中,并实现了多个处理事件;
 MainActiviy在跳转时发布了sticky事件,SecondActity取出了sticky事件;
 SecondActivity的3个按钮分别发布了几个事件,用于测试默认的EventBus、建造者模式生成的EventBus。

参考
[1]EventBus使用详解(一)——初步使用EventBus;
[2]https://www.zhihu.com/question/32179258/answer/54989242;
[3] http://www.2cto.com/kf/201503/380502.html。

说你懂得生之微末,我便做了这壮大与你看,你说再热闹也终需离散,我便做了这一辈子与你看,你说冷暖自知,我便做了这冬花夏雪与你看,你说恋恋旧日好时光,我便做了这描金绣凤的浮世绘与你看。你说应愁高处不胜寒,我便拱手河山,讨你欢。