Android框架式编程之EventBus
一、EventBus 简介
EventBus是一种用于Android的事件发布-订阅总线,由GreenRobot开发,Gihub地址是:EventBus。
它简化了应用程序内各个组件之间进行通信的复杂度,尤其是碎片之间进行通信的问题,可以避免由于使用广播通信而带来的诸多不便。
1. EventBus的三个角色
Event:事件,它可以是任意类型,EventBus会根据事件类型进行全局的通知。
Subscriber:事件订阅者,在EventBus 3.0之前我们必须定义以onEvent开头的那几个方法,分别是
onEvent
、onEventMainThread
、onEventBackgroundThread
和onEventAsync
,而在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,发布事件并返回。第一次的时候,这里的两个订阅方法都会被触发。然后,我们按下停止分发的按钮,并再次执行上面的逻辑,此时只有优先级较高的方法获取到了事件并将该事件终止。
Android框架式编程之EventBus的更多相关文章
- Android框架式编程之Android Architecture Components
1. 当前Android开发面临的问题 Android开发不同于传统的桌面程序开发,桌面程序一般都有唯一的快捷方式入口,并且常作为单进程存在:而一个典型的Android应用通常由多个应用组件构成,包括 ...
- Android框架式编程之BufferKnife
配置 compile 'com.jakewharton:butterknife:(insert latest version)' annotationProcessor 'com.jakewharto ...
- Android框架式编程之RxJava(一):HelloWorld
Hello World 源码: import android.graphics.Bitmap; import android.graphics.BitmapFactory; import androi ...
- Android框架式编程之Room
Room是Google官方出品的ORM(Object-relational mapping) 框架.当前我们也知道当前还有很多的ORM框架,例如GreenDao.OrmLite.Litepal等.目前 ...
- Android框架式编程之Retrofit
一.Retrofit 简介 Retrofit 官网地址: https://github.com/square/retrofit Retrofit(即Retrofit,目前最新版本为2.6.0版本),是 ...
- Android框架式编程之Lifecycle
Lifecycle官方文档地址:https://developer.android.com/topic/libraries/architecture/lifecycle. 一.为什么要使用Lifecy ...
- Android框架式编程之EasyPermissions
EasyPermission库是一个谷歌官方提供的简化基本的系统权限逻辑的库,可用于在Android M或者更高版本上. 官方项目地址:https://github.com/googlesamples ...
- Android框架式编程之LiveData
一.LiveData 介绍 LiveData是 Google 推荐的 Android 架构组件之一,是一个基于观察者模式的数据容器,但与一般的被观察者不同的是,它是有生命周期感知功能,解决了Andro ...
- Android框架式编程之MVP架构
MVP(Model-View-Presenter)模式.是将APP的结构分为三层:View - Presenter - Model. View 1. 提供UI交互 2. 在presenter的控制下修 ...
随机推荐
- iOS-关于一些取整方式
1. 直接转化 float k = 1.6; int a = (int)k; NSLog(@"a = %d",a); 输出结果是1,(int) 是强制类型转化,直接丢弃浮点数的小数 ...
- 区块链技术驱动金融.mobi
链接:https://pan.baidu.com/s/1yY8f_PglsPoudb76nru9Ig 提取码:c58o 想一起学习区块链的朋友可以加好友一个学习哦,共同进步
- react---css3动画 react-transition-group的使用
react中可以通过state状态值来控制类名,来达到动画效果 父组件代码: import React from 'react'; import SubComponent from "./s ...
- 基于XML的开发
基于XML的开发 1.定义一个切面类 /** * Created by zejian on 2017/2/20.*/ public class MyAspectXML { public void be ...
- Information Management System
Information Management System 一.代码部分 #include <stdio.h> #include <stdlib.h> #include < ...
- React: 高阶组件(HOC)
一.简介 如我们所知,JavaScript有高阶函数这么一个概念,高阶函数本身是一个函数,它会接收或者返回一个函数,进而对该函数进行操作.其实,在React中同样地有高阶组件这么一个东西,称为HOC, ...
- RedisSession (自定义)
RedisSession (自定义) 疯狂创客圈 Java 高并发[ 亿级流量聊天室实战]实战系列 [博客园总入口 ] 架构师成长+面试必备之 高并发基础书籍 [Netty Zookeeper Red ...
- Docker + WordPress搭建个人博客
WordPress是目前非常受欢迎的开源博客系统,今天使用Docker + WordPress搭建个人博客,整个过程非常丝滑. 搭博客先要准备域名和服务器,昨天在阿里云买了个.top的域名花了5块钱( ...
- Spring Boot Security 保护你的程序
Spring Boot Security 本示例要内容 基于角色的权限访问控制 加密.解密 基于Spring Boot Security 权限管理框架保护应用程序 String Security介绍 ...
- tornado框架中redis使用
一.安装依赖 pip3 install tornado-redis 二.导入模块 import tornadoredis 三.创建redis对象 import tornadoredis CONNECT ...