一、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. .NET Core 3.0正式版发布

    是的,.NET Core 3.0正式版发布了,令人兴奋. WPF 其实,.NET Core 2.1开始已经是个很完善的版本,3.0又带来了什么呢?我站在我的使用角度来看,最最令人振奋的就是:能用WPF ...

  2. 使用 ASP.NET Core MVC 创建 Web API(六)

    使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 使 ...

  3. Mysql - 高可用方案之MMM(一)

    一.概述 本文将介绍mysql的MMM(Master-Master replication manager for MySQL)方案.官方文档地址:https://mysql-mmm.org/star ...

  4. 【HNOI 2019】JOJO

    Problem Description JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 \(x\) ...

  5. 在 .NET Core 3.0 中支持 Newtonsoft.Json 的使用

    .NET Core 3.0 已经使用了一整套内置的 Josn 序列化/反序列化方案,而且看上去效率还不错.但对于某些项目必须使用到 Newtonsoft.Json 的时候,就会抛出如下异常: Syst ...

  6. C# Task 多任务 限制Task并发数量

    LimitedTaskScheduler: using System; using System.Collections.Concurrent; using System.Collections.Ge ...

  7. ubuntu安装navicat

    ubuntu下安装navicat1.官网下载https://www.navicat.com.cn/download/navicat-premium,不清楚系统是32位的还是64位的,可以用”uname ...

  8. Flask 教程 第十四章:Ajax

    本文翻译自The Flask Mega-Tutorial Part XIV: Ajax 这是Flask Mega-Tutorial系列的第十四部分,我将使用Microsoft翻译服务和少许JavaSc ...

  9. DispatchProxy实现动态代理及AOP

    DispatchProxy类是DotnetCore下的动态代理的类,源码地址:Github,官方文档:MSDN.主要是Activator以及AssemblyBuilder来实现的(请看源码分析),园子 ...

  10. kotlin之变量与常量

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/217 kotlin之变量与常量 最近开始做新产品,于是乎用 ...