一、EventBus 简介

EventBus是一种用于Android的事件发布-订阅总线,由GreenRobot开发,Gihub地址是:EventBus

它简化了应用程序内各个组件之间进行通信的复杂度,尤其是碎片之间进行通信的问题,可以避免由于使用广播通信而带来的诸多不便。

1. EventBus的三个角色

  • Event:事件,它可以是任意类型,EventBus会根据事件类型进行全局的通知。

  • Subscriber:事件订阅者,在EventBus 3.0之前我们必须定义以onEvent开头的那几个方法,分别是onEventonEventMainThreadonEventBackgroundThreadonEventAsync,而在3.0之后事件处理的方法名可以随意取,不过需要加上注解@subscribe,并且指定线程模型,默认是POSTING

  • Publisher:事件的发布者,可以在任意线程里发布事件。一般情况下,使用EventBus.getDefault()就可以得到一个EventBus对象,然后再调用post(Object)方法即可。

2. 四种线程模型

EventBus3.0有四种线程模型,分别是:

  • POSTING:默认,表示事件处理函数的线程跟发布事件的线程在同一个线程。
  • MAIN:表示事件处理函数的线程在主线程(UI)线程,因此在这里不能进行耗时操作。
  • BACKGROUND:表示事件处理函数的线程在后台线程,因此不能进行UI操作。如果发布事件的线程是主线程(UI线程),那么事件处理函数将会开启一个后台线程,如果果发布事件的线程是在后台线程,那么事件处理函数就使用该线程。
  • ASYNC:表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个子线程运行,同样不能进行UI操作。

二、EventBus 使用

1. 引入依赖

在使用之前先要引入如下依赖:

implementation 'org.greenrobot:eventbus:3.1.1'

2. 定义事件

定义一个事件的封装对象。在程序内部就使用该对象作为通信的信息:

public class MessageWrap {

    public final String message;

    public static MessageWrap getInstance(String message) {
return new MessageWrap(message);
} private MessageWrap(String message) {
this.message = message;
}
}

在定义事件对象的时候,而我们可以对字段进行拓展,方便后期的使用和维护。

3. 发布事件

然后,我们定义一个Activity:

@Route(path = BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY1)
public class EventBusActivity1 extends CommonActivity<ActivityEventBus1Binding> { @Override
protected void doCreateView(Bundle savedInstanceState) {
// 为按钮添加添加单击事件
getBinding().btnReg.setOnClickListener(v -> EventBus.getDefault().register(this));
getBinding().btnNav2.setOnClickListener( v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY2)
.navigation());
} @Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
} @Subscribe(threadMode = ThreadMode.MAIN)
public void onGetMessage(MessageWrap message) {
getBinding().tvMessage.setText(message.message);
}
}

这里我们当按下按钮的时候向EventBus注册监听,然后按下另一个按钮的时候跳转到拎一个Activity,并在另一个Activity发布我们输入的事件。在上面的Activity中,我们会添加一个监听的方法,即onGetMessage,这里我们需要为其加入注解Subscribe并指定线程模型为主线程MAIN。最后,就是在Activity的onDestroy方法中取消注册该Activity。

下面是另一个Activity的定义,在这个Activity中,我们当按下按钮的时候从EditText中取出内容并进行发布,然后我们退出到之前的Activity,以测试是否正确监听到发布的内容。

@Route(path = BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY2)
public class EventBusActivity2 extends CommonActivity<ActivityEventBus2Binding> { @Override
protected void doCreateView(Bundle savedInstanceState) {
getBinding().btnPublish.setOnClickListener(v -> publishContent());
} private void publishContent() {
String msg = getBinding().etMessage.getText().toString();
EventBus.getDefault().post(MessageWrap.getInstance(msg));
ToastUtils.makeToast("Published : " + msg);
}
}

根据测试的结果,我们的确成功地接收到了发送的信息。

4. 黏性事件

所谓的黏性事件,就是指发送了该事件之后再订阅者依然能够接收到的事件。使用黏性事件的时候有两个地方需要做些修改。一个是订阅事件的地方,这里我们在先打开的Activity中注册监听黏性事件:

@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onGetStickyEvent(MessageWrap message) {
String txt = "Sticky event: " + message.message;
getBinding().tvStickyMessage.setText(txt);
}

另一个是发布事件的地方,这里我们在新的开的Activity中发布黏性事件。即调用EventBus的postSticky方法来发布事件:

private void publishStickyontent() {
String msg = getBinding().etMessage.getText().toString();
EventBus.getDefault().postSticky(MessageWrap.getInstance(msg));
ToastUtils.makeToast("Published : " + msg);
}

按照上面的模式,我们先在第一个Activity中打开第二个Activity,然后在第二个Activity中发布黏性事件,并回到第一个Activity注册EventBus。根据测试结果,当按下注册按钮的时候,会立即触发上面的订阅方法从而获取到了黏性事件。

5. 优先级

Subscribe注解中总共有3个参数,上面我们用到了其中的两个,这里我们使用以下第三个参数,即priority。它用来指定订阅方法的优先级,是一个整数类型的值,默认是0,值越大表示优先级越大。在某个事件被发布出来的时候,优先级较高的订阅方法会首先接受到事件。

为了对优先级进行测试,这里我们需要对上面的代码进行一些修改。这里,我们使用一个布尔类型的变量来判断是否应该取消事件的分发。我们在一个较高优先级的方法中通过该布尔值进行判断,如果未true就停止该事件的继续分发,从而通过低优先级的订阅方法无法获取到事件来证明优先级较高的订阅方法率先获取到了事件。

这里有几个地方需要注意

1. 只有当两个订阅方法使用相同的ThreadMode参数的时候,它们的优先级才会与priority指定的值一致;

2. 只有当某个订阅方法的ThreadMode参数为POSTING的时候,它才能停止该事件的继续分发。

所以,根据以上的内容,我们需要对代码做如下的调整:

// 用来判断是否需要停止事件的继续分发
private boolean stopDelivery = false; @Override
protected void doCreateView(Bundle savedInstanceState) {
// ... getBinding().btnStop.setOnClickListener(v -> stopDelivery = true);
} @Subscribe(threadMode = ThreadMode.POSTING, priority = )
public void onGetMessage(MessageWrap message) {
getBinding().tvMessage.setText(message.message);
} // 订阅方法,需要与上面的方法的threadMode一致,并且优先级略高
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true, priority = )
public void onGetStickyEvent(MessageWrap message) {
String txt = "Sticky event: " + message.message;
getBinding().tvStickyMessage.setText(txt);
if (stopDelivery) {
// 终止事件的继续分发
EventBus.getDefault().cancelEventDelivery(message);
}
}

即我们在之前的代码之上增加了一个按钮,用来将stopDelivery的值置为true。该字段随后将会被用来判断是否要终止事件的继续分发,因为我们需要在代码中停止事件的继续分发,所以,我们需要将上面的两个订阅方法的threadMode的值都置为ThreadMode.POSTING

按照,上面的测试方式,首先我们在当前的Activity注册监听,然后跳转到另一个Activity,发布事件并返回。第一次的时候,这里的两个订阅方法都会被触发。然后,我们按下停止分发的按钮,并再次执行上面的逻辑,此时只有优先级较高的方法获取到了事件并将该事件终止。

参考资料:https://www.jianshu.com/p/e7d5c7bda783

Android框架式编程之EventBus的更多相关文章

  1. Android框架式编程之Android Architecture Components

    1. 当前Android开发面临的问题 Android开发不同于传统的桌面程序开发,桌面程序一般都有唯一的快捷方式入口,并且常作为单进程存在:而一个典型的Android应用通常由多个应用组件构成,包括 ...

  2. Android框架式编程之BufferKnife

    配置 compile 'com.jakewharton:butterknife:(insert latest version)' annotationProcessor 'com.jakewharto ...

  3. Android框架式编程之RxJava(一):HelloWorld

    Hello World 源码: import android.graphics.Bitmap; import android.graphics.BitmapFactory; import androi ...

  4. Android框架式编程之Room

    Room是Google官方出品的ORM(Object-relational mapping) 框架.当前我们也知道当前还有很多的ORM框架,例如GreenDao.OrmLite.Litepal等.目前 ...

  5. Android框架式编程之Retrofit

    一.Retrofit 简介 Retrofit 官网地址: https://github.com/square/retrofit Retrofit(即Retrofit,目前最新版本为2.6.0版本),是 ...

  6. Android框架式编程之Lifecycle

    Lifecycle官方文档地址:https://developer.android.com/topic/libraries/architecture/lifecycle. 一.为什么要使用Lifecy ...

  7. Android框架式编程之EasyPermissions

    EasyPermission库是一个谷歌官方提供的简化基本的系统权限逻辑的库,可用于在Android M或者更高版本上. 官方项目地址:https://github.com/googlesamples ...

  8. Android框架式编程之LiveData

    一.LiveData 介绍 LiveData是 Google 推荐的 Android 架构组件之一,是一个基于观察者模式的数据容器,但与一般的被观察者不同的是,它是有生命周期感知功能,解决了Andro ...

  9. Android框架式编程之MVP架构

    MVP(Model-View-Presenter)模式.是将APP的结构分为三层:View - Presenter - Model. View 1. 提供UI交互 2. 在presenter的控制下修 ...

随机推荐

  1. 利用zabbix监控RocketMQ

    根据需求,监控三个指标:MQ进程.自定义监控项订阅组的未消费值Diff Total和TPS. 创建MQ 状态的监控模板,进程监控利用zabbix自带的模板: 监控订阅组的Diff Total和TPS ...

  2. Cesium专栏-地形开挖2-任意多边形开挖(附源码下载)

    “任意多边形地形开挖” 是“地形开挖”的补充篇,在这节里,我们介绍关于如何使用任意多边形对地形进行开挖,同时,由于有不少小伙伴也咨询了关于“地形开挖”篇后序内容中的填充地形的效果,之前没放出来,是想让 ...

  3. Android 上下文菜单 ContextMenu

    public class MainActivity extends Activity { private ListView listView; @Override protected void onC ...

  4. [洛谷P1967][题解]货车运输

    题目 这道题让我们求最小限重的最大值 显然可以先求出最大生成树,然后在树上进行操作 因为如果两点之间有多条路径的话一定会走最大的,而其他小的路径是不会被走的 然后考虑求最小权值 可以采用倍增求LCA, ...

  5. EggJS接口开发

    需求 随着Nodejs的普及,前端开发的开发场景基本可以贯穿界面交互到数据存储,无缝实现全栈开发.最近在实现一个内部项目管理工具的时候,就尝试了一把接口和数据库开发. 什么是Egg.js Egg.js ...

  6. Power BI 概念及 国内版Pro 试用账户注册流程

    视频内容: Power BI 基本概念:https://v.qq.com/x/page/s3026nn69eu.html Power BI Pro 世纪互联版本试用账号注册:https://v.qq. ...

  7. Java题库——Chapter14 JavaFX基础

    Chapter 14 JavaFX Basics Section 14.2 JavaFX vs Swing and AWT1. Why is JavaFX preferred?a. JavaFX is ...

  8. .NET Core AES-CCM&AES-GCM加密算法

    一. 前言 关于 CCM 以及 GCM 看此文( CCM和GCM )或者直接搜索网上资料. .NET Core 3.0 实现了对AES-GCM和AES-CCM加密的支持.这些算法既是带有关联数据的身份 ...

  9. Vue+ElementUI的后台管理框架

    新开发的一个后台管理系统.在框架上,领导要用AdminLTE这套模板.这个其实很简单,把该引入的样式和js文件引入就可以了.这里就不多赘述了.有兴趣的可以参考:https://www.jianshu. ...

  10. 团队项目之Alpha阶段项目复审

    组的名字和链接 优点 缺点,bug报告 最终名次 六姑娘 https://www.cnblogs.com/liujiamei/p/11992659.html 团队的小程序功能齐全,这说明团队在需求分析 ...