一、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. 引入依赖

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

  1. implementation 'org.greenrobot:eventbus:3.1.1'

2. 定义事件

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

  1. public class MessageWrap {
  2.  
  3. public final String message;
  4.  
  5. public static MessageWrap getInstance(String message) {
  6. return new MessageWrap(message);
  7. }
  8.  
  9. private MessageWrap(String message) {
  10. this.message = message;
  11. }
  12. }

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

3. 发布事件

然后,我们定义一个Activity:

  1. @Route(path = BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY1)
  2. public class EventBusActivity1 extends CommonActivity<ActivityEventBus1Binding> {
  3.  
  4. @Override
  5. protected void doCreateView(Bundle savedInstanceState) {
  6. // 为按钮添加添加单击事件
  7. getBinding().btnReg.setOnClickListener(v -> EventBus.getDefault().register(this));
  8. getBinding().btnNav2.setOnClickListener( v ->
  9. ARouter.getInstance()
  10. .build(BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY2)
  11. .navigation());
  12. }
  13.  
  14. @Override
  15. protected void onDestroy() {
  16. super.onDestroy();
  17. EventBus.getDefault().unregister(this);
  18. }
  19.  
  20. @Subscribe(threadMode = ThreadMode.MAIN)
  21. public void onGetMessage(MessageWrap message) {
  22. getBinding().tvMessage.setText(message.message);
  23. }
  24. }

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

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

  1. @Route(path = BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY2)
  2. public class EventBusActivity2 extends CommonActivity<ActivityEventBus2Binding> {
  3.  
  4. @Override
  5. protected void doCreateView(Bundle savedInstanceState) {
  6. getBinding().btnPublish.setOnClickListener(v -> publishContent());
  7. }
  8.  
  9. private void publishContent() {
  10. String msg = getBinding().etMessage.getText().toString();
  11. EventBus.getDefault().post(MessageWrap.getInstance(msg));
  12. ToastUtils.makeToast("Published : " + msg);
  13. }
  14. }

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

4. 黏性事件

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

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

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

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

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

5. 优先级

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

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

这里有几个地方需要注意

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

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

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

  1. // 用来判断是否需要停止事件的继续分发
  2. private boolean stopDelivery = false;
  3.  
  4. @Override
  5. protected void doCreateView(Bundle savedInstanceState) {
  6. // ...
  7.  
  8. getBinding().btnStop.setOnClickListener(v -> stopDelivery = true);
  9. }
  10.  
  11. @Subscribe(threadMode = ThreadMode.POSTING, priority = )
  12. public void onGetMessage(MessageWrap message) {
  13. getBinding().tvMessage.setText(message.message);
  14. }
  15.  
  16. // 订阅方法,需要与上面的方法的threadMode一致,并且优先级略高
  17. @Subscribe(threadMode = ThreadMode.POSTING, sticky = true, priority = )
  18. public void onGetStickyEvent(MessageWrap message) {
  19. String txt = "Sticky event: " + message.message;
  20. getBinding().tvStickyMessage.setText(txt);
  21. if (stopDelivery) {
  22. // 终止事件的继续分发
  23. EventBus.getDefault().cancelEventDelivery(message);
  24. }
  25. }

即我们在之前的代码之上增加了一个按钮,用来将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. Supermap/Cesium 开发心得----动态散点图(波纹点/涟漪点)

    在二维开发中,openlayers4 入门开发系列结合 echarts4 实现散点图,下图是GIS之家的效果图,那么在三维中,则可借助Entity来变相构造下图的效果. 思路: 构造实体ellipse ...

  2. 【目录】Cocos2d-x系列

    1.Cocos2d-x的坐标系统 2.Cocos2d-x 点击菜单按键居中放大(无需修改底层代码) 3.发布Cocos2d-x的PC端程序 4.Cocos2d-x游戏实例<忍者飞镖>之对象 ...

  3. Java基础语法02-流程控制-if-switch-for-while

    流程控制语句 顺序结构 任何编程语言中最常见的程序结构就是顺序结构.顺序结构就是程序从上到下逐行地执行,中间没有任何判断和跳转. 分支结构 if(条件表达式){ 语句体;} 执行流程 首先判断条件表达 ...

  4. 简约清新立体商务年终工作总结汇报动态PPT模板

    模版来源:http://ppt.dede58.com/gongzuohuibao/26682.html

  5. JDK新特性关于流操作部分

    // array 工具类 可以用来快捷的将数组转化为list List<String> strings = Arrays.asList("zhongguo", &quo ...

  6. reports buileder 触发器的写法

    触发器写法: function CF_SHOULD_BACK_TIMEFormula return Number is--其他:取MES工时按工段分别统计产量.投入工时合计:应回报工时=移动数量*[∑ ...

  7. latex 添加Bibtex 全解(使用TeXstudio)

    前提知识: 生成pdf的一般流程 在使用Latex之前,我们一般会借用已有的论文模板,在模板基础上加入我们自己的文章内容,随后编译成PDF文件,其基本流程就是:Latex->Bibtex-> ...

  8. SQL Server优化技巧——如何避免查询条件OR引起的性能问题

    之前写过一篇博客"SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析",里面介绍了OR可能会引起全表扫描或索引扫描的各种案例,以及如何优化查询条件中含有OR的SQL语句的 ...

  9. jquery dialog的一些坑

    jquery dialog工具可以方便的生成一个弹出框,但是在一些需要多个弹出框的应用场景上会有一些bug 具体场景: 当使用过一次模态框之后,使用另外的一个模态框时,已经消失不见的模态框会重新出来 ...

  10. java之数据结构

    数据结构有什么用? 现实世界的存储,我们使用的工具和建模.每种数据结构有自己的优点和缺点,想想如果Google的数据用的是数组的存储,我们还能方便地查询到所需要的数据吗?而算法,在这么多的数据中如何做 ...