EventBus 3.1.1(线程间!!!)

目录一 EventBus 3.1.11.1.简介1.2.实现1.2.1.配置(EventBusBuilder)1.2.2.声明事件类型1.2.3.在订阅者类中定义消息处理方法(事件回调方法)1.2.4.在订阅者类中注册解绑EventBus1.2.5.被订阅者类发送事件对象1.3.线程模型(ThreadMode)1.3.1.ThreadMode.POSTING...
摘要由CSDN通过智能技术生成

目录

一 EventBus 3.1.1

1.1.简介

1.2.实现

1.2.1.配置(EventBusBuilder)

1.2.2.声明事件类型

1.2.3.在订阅者类中定义消息处理方法(事件回调方法)

1.2.4.在订阅者类中注册解绑EventBus

1.2.5.被订阅者类发送事件对象

1.3.线程模型(ThreadMode)

1.3.1.ThreadMode.POSTING

1.3.2.ThreadMode.MAIN

1.3.3.ThreadMode.BACKGROUND

1.3.4.ThreadMode.ASYNC

1.4.粘性事件(StickyEvent)

1.4.1.场景分析:

1.4.2.StickyEvent:

1.4.3.实现:

1.4.4.应用案例:

1.5.无订阅者事件(NoSubscriberEvent)

1.6.事件优先级(priority)

1.7.终止事件传递

1.8.EventBus processor使用

1.8.1.配置索引:在build.gradle中添加如下配置

1.8.2.使用索引:

1.9.混淆

二 EventBus 3.1.1源码解析(原理)

2.1.构造

2.1.1.getDefault():DCL双检锁单例模式

2.1.2.EventBus():无参构造方法

2.1.3.builder():自定义建造者

2.1.4.EventBus 最终构建过程

2.2.注册

2.2.1.获取订阅者subscriber的Class类型

2.2.2.通过Class subscriberClass解析出订阅者声明的所有事件处理方法、方法参数类型

2.2.3.subscribe(subscriber, subscriberMethod)方法的实现

2.3.发送消息

2.3.1.post

2.3.2.postSticky

2.3.3.postSingleEvent

2.3.4.postSingleEventForEventType

2.3.5.postToSubscription

2.3.6.invokeSubscriber

2.4.解绑

三 EventBus和OTTO对比


一 EventBus 3.1.1

1.1.简介

简介:

EventBus是一个基于观察者模式的事件发布 / 订阅的消息总线框架。目的用于简化(Android)组件、线程间通讯,可轻易切换、开辟线程,简洁,方便,体积小,效率高 ……

EventBus3.0跟先前版本的区别在于加入了annotation @Subscribe,取代了以前约定命名的方式。

原理:

EventBus中,被观察者(事件对象)产生或变更的时候,会通过EventBus把 事件对象“通知给”观察者(订阅者对象)(触发事件回调方法)。整个过程中EventBus充当了中介的角色,将原本 被观察者(事件对象)所需要承担的责任抽离出来由自己承担,缓存并管理 观察者 列表,并与 被观察者(事件对象)建立对应关系,并控制时机,将被 观察者(事件对象)“通知给” 观察者(订阅者对象)

EventBus中 被观察者观察者 是通过 声明的 事件对象类型(可以理解为一种协议) 进行匹配的,即EventBus将特定的 事件对象 发送给能接收该 事件类型订阅者对象(订阅者在注册EventBus的时候,就已经告诉EventBus,自己需要哪类事件了)。

优:

代码够简洁,消息发布者和订阅者之间的耦合度够低!并且可以动态设置事件处理线程以及优先级。快速,轻量!

劣:

每个事件都要创建一个事件类,加大维护成本(可做封装优化,后面会介绍方案)。

说明:

由于EventBus使用了反射,关于性能问题 ……

EventBus不仅可以使用注解处理器预处理获取订阅信息,也会将订阅者的方法缓存到METHOD_CACHE里避免重复查找,只有在最后invoke()方法的时候会比直接调用多出一些性能损耗,其实可以忽略不计。

结构图:

SDK

EventBus :http://greenrobot.org/eventbus/

GitHub:https://github.com/greenrobot/EventBus

version

http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22

https://mvnrepository.com/

注意:

com.google.common.eventbus. EventBus

org.greenrobot.eventbus.EventBus

两个EventBus不一样

1.2.实现

(1)订阅者类中需要注册和解绑EventBus

(2)声明事件类型

(3)在事件产生或者变更的类中直接post事件对象。

1.2.1.配置(EventBusBuilder)

EventBusBuilder提供了EventBus的配置接口,指定了EventBus的一些行为,用于输出log,查错,调试等。比如配置日志输出模式(开发版本/发布版本),配置错误处理模式(开发版本遇错误崩溃 / 发布版本遇错误崩溃)等等。

// 修改默认实现的配置:debug模式下要抛出异常  
EventBus.builder().throwSubscriberException(BuildConfig.DEBUG)

        .installDefaultEventBus();

必须在第一次EventBus.getDefault()之前配置,且只能设置一次。建议在application.onCreate()调用。

installDefaultEventBus这个方法用来将一个自定义的EventBusBuider对象配置到EventBus中去,并替换掉defaultInstance。

注意:这里需要在Default EventBus 对象还没生成的时候执行这段代码。如果已经有默认的EventBus对象存在了再installDefaultEventBus就会抛异常。所以最好在app启动的时候加入代码!

1.2.2.声明事件类型

public class MessageEvent {
  
    public final String message;

    public MessageEvent(String message) {

        this.message = message;

    }

}

1.2.3.在订阅者类中定义消息处理方法(事件回调方法)

@Subscribe
public void onMessageEvent(MessageEvent event) {

    Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();

}

// This method will be called when a SomeOtherEvent is posted

@Subscribe

public void handleSomethingElse(SomeOtherEvent event) {

    doSomethingWith(event);

}

@Subscribe(threadMode = ThreadMode.POSTING)

public void onMessageEvent(MessageEvent event) {

    doSomethingWith(event);

}

事件处理函数的访问权限必须为public!!!

在3.0之前,事件处理的方法也只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,分别代表四种线程模型;在3.0之后,消息处理的方法可以随便取名,只需要添加一个注解@Subscribe,并且要指定线程模型(默认为POSTING

1.2.4.在订阅者类中注册解绑EventBus

@Override
public void onStart() {

    super.onStart();

    EventBus.getDefault().register(this);

}

@Override

public void onStop() {

    EventBus.getDefault().unregister(this);

    super.onStop();

}

1.2.5.被订阅者类发送事件对象

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

1.3.线程模型(ThreadMode)

1.3.1.ThreadMode.POSTING

说明:

事件发布线程中执行(默认线程模型):事件在哪个线程发布(post),事件接收方法就在哪个线程中执行,即 发布事件 和 接收处理事件 在同一个线程。当该线程为主线程时,响应方法中不能有耗时操作,否则有卡主线程的风险,甚至有可能会引起ANR。

场景:

对于是否在主线程执行无要求,但若 Post 线程为主线程,不能处理耗时操作

// Called in the same thread (default)
@Subscribe(threadMode = ThreadMode.POSTING)

public void onMessageEvent(MessageEvent messageEvent) {

    doSomethingWith(event);

}

1.3.2.ThreadMode.MAIN

说明:

主线程(UI线程)中执行:如果事件发布线程就是主线程,则直接调用订阅者的事件回调方法,否则将通过主线程的 Handler 发送消息,通知订阅者在主线程中处理事件回调。

场景:

该线程模式可以用来更新UI,但是 不能处理耗时操作

// Called in Android UI's main thread
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent messageEvent) {
    doSomethingWith(event);
}

1.3.3.ThreadMode.BACKGROUND

说明:

后台线程中执行:如果事件发布线程不是主线程,则直接在该线程执行;否则,切换到后台单例线程执行事件回调方法,且多个方法公用同个后台线程,按顺序执行。

场景:

禁止进行UI更新操作,或禁止在主线程(UI线程)中执行,同样 避免处理耗时操作!

// Called in the background thread
@Subscribe(threadMode = ThreadMode. BACKGROUND)
public void onMessageEvent(MessageEvent messageEvent) {
    doSomethingWith(event);
}

1.3.4.ThreadMode.ASYNC

说明:

异步线程执行:开辟新独立线程,EventBus内部使用了线程池,但是要尽量避免大量长时间运行的异步线程,限制并发线程数量可以通过EventBusBuilder修改,默认使用Executors.newCachedThreadPool()。

场景:

用来执行耗时操作,例如网络访问。

// Called in a separate thread
@Subscribe(threadMode = ThreadMode. ASYNC)
public void onMessageEvent(MessageEvent messageEvent) {
    doSomethingWith(event);
}

1.4.粘性事件(StickyEvent)

1.4.1.场景分析:

1.背景描述:

正常事件发布处理流程应该是订阅者先在EventBus中注册,并告诉EventBus自己想订阅哪些类型的事件。之后当事件发布时,才有可能通过EventBus找到匹配的订阅者。然而,会有一种场景是事件先发布,订阅者之后才注册,这种情况下,事件发布时是找不到订阅者的 …… StickyEvent就是为了解决上述问题而生的。

2.具体应用场景:

(1)缓存:EventBus会将StickyEvent特定类型的最后一个实体保留在内存中,并可供明确查询。

(2)替代Intent传递数据给新的Activity

1.4.2.StickyEvent:

StickyEvent类似广播分类中的粘性广播,同类Event会一直在内存中保存最新的实体,覆盖原有实体。当检查到有可匹配的订阅者在EventBus注册的时候,EventBus会找到订阅者并将最新的实体“通知给”订阅者。如果没有可匹配的订阅者注册,Event消息实体会一直保留在内存中。

如此一来,订阅在发布事件之后,同样可以收到事件,且EventBus会在订阅者订阅之后立即找到它并回调其粘性事件处理方法。订阅/解除订阅和普通事件一样,但是声明事件回调方法稍有不同,需要注解中添加sticky = true。

订阅在发布事件之后的场景中,必须使用postSticky方法发布事件,且必须使用注解中添加sticky = true的事件处理方法接收sticky事件。

实现原理:

postSticky中用了一个stickyEvents (ConcurrentHashMap< event.getClass(), event>)缓存了最新的事件实体。

public void postSticky(Object event) {
    synchronized (stickyEvents) {
        stickyEvents.put(event.getClass(), event);
    }
    // Should be posted after it is putted, in case the subscriber wants to remove immediately
    post(event);
}

1.4.3.实现:

声明事件处理方法:

@Subscribe(threadMode = ThreadMode.MAIN,sticky = true) // 在ui线程执行
public void stickyEventMethod(MessageEvent event) {

    // ......

}

事件发送:

EventBus.getDefault().postSticky(new MessageEvent ());

由于StickyEvent属于常驻事件,会常驻内存,所以有时候需要手动移除!

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);

    //or

    EventBus.getDefault().removeAllStickyEvents();

    // Now do something with it

}

1.4.4.应用案例:

针对1.5.1 具体应用场景(2):替代Intent实现Activity间数据传递

(1)声明一个新的Activity B,并定义好StickyEvent事件处理方法,在onStart、onStop方法中注册 / 解注 EventBus。

public class ActivityB extends AppCompatActivity {
    @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }
    @Subscribe(sticky = true)
    public void dealSticky(StickyMessageEvent event) {
        Log.i("DemoActivity", "dealSticky method" + event);
    }
    @Override
    protected void onStop() {
        super.onStop();
        EventBus.getDefault().unregister(this);
    }
}

(2)在原Activity A中启动新Activity B之前,发布包含数据信息的StickyMessageEvent,之后启动Activity B。

EventBus.getDefault().postSticky(new StickyMessageEvent());
Intent intent = new Intent();
intent.setClass(this,  DemoActivity.class);
startActivity(intent);

(3)在Activity B中正常接收到StickyMessageEvent,解析其中数据信息进行处理 ……

1.5.无订阅者事件(NoSubscriberEvent)

没有订阅者的消息默认会被重新包装为NoSubscriberEvent,并打印Logcat:

No subscribers registered for event class org.greenrobot.eventbus.NoSubscriberEvent

可以做一些全局捕获处理,也可以通过EventBusBuilder设置是否默认发送NoSubscriberEvent,默认是打开的。(当设置为false,上述logcat就不会打印了)

EventBus.builder().sendNoSubscriberEvent(false).installDefaultEventBus();

1.6.事件优先级(priority)

priority越大,级别越高,越优先获得消息

@Subscribe(threadMode = ThreadMode.MAIN,priority = 100)

1.7.终止事件传递

发送有序广播可以终止广播的继续往下传递,EventBus也实现了此功能

// 优先级高的订阅者可以终止事件往下传
EventBus.getDe
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值