Android开发学习之路-EventBus使用
EventBus是一个通过发布、订阅事件实现组件间消息传递的工具。
它存在的目的,就是为了优化组件之间传递消息的过程。传统组件之间传递消息的方法有使用广播,回调等,而这些方法使用都比较复杂。
工作原理:

依赖:
 dependencies {
     compile 'org.greenrobot:eventbus:3.0.0'
 }
注:EventBus是事件-订阅模型,实际上事件就是消息,订阅就是接收,本文不会很严格区分,方便理解为主!
1. 从简单的入手:充当Handler
既然能发送消息,那么自然在同一个组件下也能进行消息的发送和接收,也就是Handler的职责。
先定义一个事件的对象:
 public class MessageEvent {
     private String message;
     public MessageEvent(String message) {
         this.message = message;
     }
     public String getMessage() {
         return message;
     }
     @Override
     public String toString() {
         return message;
     }
 }
这个事件对象只需要是Object的子类,没其他要求,消息的内容可以随意定,这里用一个String表示事件的消息,toString直接输出事件的内容。
在需要接收消息的组件中,进行EventBus的绑定,这里由Activity充当订阅者(Subscriber),也就是消息接收者。
 public class MainActivity extends AppCompatActivity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
     }
     @Override
     protected void onStart() {
         super.onStart();
         EventBus.getDefault().register(this); // 将当前Activity绑定为订阅者
     }
     @Override
     protected void onStop() {
         EventBus.getDefault().unregister(this); // 解绑
         super.onStop();
     }
     // 声明一个订阅方法,用于接收事件
     @Subscribe
     public void onEvent(MessageEvent messageEvent) {
         Log.d(TAG, "onEvent() called with: messageEvent = [" + messageEvent + "]");
     }
 }
通过EventBus.getDefault方法获取到一个EventBus的一个单例,也就是每次调用这个方法得到的都是同一个EventBus对象。而不同的EventBus对象消息不会互通。
接着需要在Activity的onStart方法中进行对EventBus对象的绑定,在onStop方法中进行解绑。同时,需要定义用于接收事件的方法,并加上@Subscribe注解表明该方法用于接收订阅事件。
接着,我们需要发送事件:
 EventBus.getDefault().post(new MessageEvent("I m Fndroid"));
这里获取的默认的EventBus对象,通过post方法进行事件的发送,log如下:

2. 组件间通讯:代替广播、回调等
EventBus的存在,并不是为了替代Handler,而是用来进行组件间的通讯。有了上面的知识,接下来就不难了。
我们都知道,只要是同一个EventBus对象绑定的组件(Subscriber),消息是互通的,也就是我们可以在Service中向Activity发送事件进行通讯。(其他组件类似)
定义一个IntentService,并且发送一个事件,而Activity,和上面一样。
 public class MyIntentService extends IntentService {
     public MyIntentService() {
         super("MyIntentService");
     }
     @Override
     protected void onHandleIntent(Intent intent) {
         EventBus.getDefault().post(new MessageEvent("From service"));
     }
 }
在Activity中开启服务:
startService(new Intent(this, MyIntentService.class));
Log:

组件间的通讯变得如此简单了。
3. 进阶:持久事件、线程模式、优先级
① 持久事件(StickyEvent):对于调用post方法发送的普通消息,会在第一次被接收到的时候被消费掉,也就是我们在@Subscribe方法下处理完了,这个消息就消失了。而EventBus则提供了另一种类型的消息——StickyEvent,这个消息,会被保存在RAM中,直到下一个StickyEvent被发送才会被替换。每个EventBus对象都能通过geStickyEvent方法获取最近发出的持久事件。
我们对Activity稍作修改,在订阅方法中,把当前的持久消息打印出来:
// 声明一个订阅方法,用于接收事件
@Subscribe
public void onEvent(MessageEvent messageEvent) {
Log.d(TAG, "onEvent() called with: messageEvent = [" + messageEvent + "]");
Log.d(TAG, "onEvent: Sticky Event = [" + EventBus.getDefault().getStickyEvent(MessageEvent.class) + "]");
}
接着对Service也进行修改,令其发送一个StickyEvent:
@Override
protected void onHandleIntent(Intent intent) {
EventBus.getDefault().post(new MessageEvent("From service"));
EventBus.getDefault().postSticky(new MessageEvent("From service2"));
EventBus.getDefault().post(new MessageEvent("From service3"));
}
这里看到,在第二次发送的时候,调用了postSticky方法发送事件,这就表明了该事件是一个持久事件,除非有新的同类型(不同类型的事件可以共存)持久事件被发送,否则会一直被保存在内存中,我们任何时候都能获取得到。
Log:

可以看到,在第三次接收到消息的时候,将StickyEvent打印出来,依旧是"From service2"。
同样的,如果我们想要移除此持久事件,可以调用EventBus的removeStickyEvent方法来实现,如果要移除所有类型的持久事件,可以调用removeAllStickyEvent方法。
② 线程模式
EventBus允许我们对订阅者进行线程设置,默认情况下,订阅是和事件发送处于同一线程的,我们不妨把订阅的线程id打印出来看一看。
修改Activity中的@Subscribe方法:
@Subscribe
public void onEvent(MessageEvent messageEvent) {
Log.d(TAG, "onEvent: Thread id = [" + Thread.currentThread().getId() + "]");
Log.d(TAG, "onEvent() called with: messageEvent = [" + messageEvent + "]");
}
修改Service,让其发送一次普通事件,并且输出当前线程id:
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent: Thread id = [" + Thread.currentThread().getId() + "]");
EventBus.getDefault().post(new MessageEvent("From service"));
}
打印Log:

对于订阅者,有以下四种线程模式:
- POSTING:默认模式,订阅和事件发送在同一线程下进行
- MAIN:订阅在主线程下进行,可以直接修改UI
- BACKGROUND:如果事件发送在主线程,则订阅在子线程下进行,如果事件发送在子线程,则订阅也在该子线程中进行
- ASYNC:如果事件发送在主线程,则订阅在子线程下进行,如果事件发送在子线程,则订阅会在其他子线程中进行
设置订阅者线程很简单,只需要在注解中赋值即可,如:
@Subscribe(threadMode = ThreadMode.MAIN)
③ 优先级
每个组件中可以有多个订阅方法,而我们可以对它们设置不同的优先级,设置的方法也很简单:
@Subscribe(priority = 88)
默认的优先级为0,更高优先级的订阅方法会更先收到事件,而每个订阅方法都可以对事件进行终止,可以通过以下方法停止事件传递:
EventBus.getDefault().cancelEventDelivery(messageEvent);
④ 自定义EventBus对象
通过getDefault方法获取的是一个EventBus默认的单例,而我们可以通过EventBus.Builder来构造一个自定义的EventBus对象。
明白了用法以后,我们分析源码也会更加简单。
Android开发学习之路-EventBus使用的更多相关文章
- Android开发学习之路-RecyclerView滑动删除和拖动排序
		Android开发学习之路-RecyclerView使用初探 Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析 Android开 ... 
- Android开发学习之路--基于vitamio的视频播放器(二)
		终于把该忙的事情都忙得差不多了,接下来又可以开始good good study,day day up了.在Android开发学习之路–基于vitamio的视频播放器(一)中,主要讲了播放器的界面的 ... 
- Android开发学习之路--Android Studio cmake编译ffmpeg
		最新的android studio2.2引入了cmake可以很好地实现ndk的编写.这里使用最新的方式,对于以前的android下的ndk编译什么的可以参考之前的文章:Android开发学习之路– ... 
- Android开发学习之路--网络编程之xml、json
		一般网络数据通过http来get,post,那么其中的数据不可能杂乱无章,比如我要post一段数据,肯定是要有一定的格式,协议的.常用的就是xml和json了.在此先要搭建个简单的服务器吧,首先呢下载 ... 
- Android开发学习之路--Activity之初体验
		环境也搭建好了,android系统也基本了解了,那么接下来就可以开始学习android开发了,相信这么学下去肯定可以把android开发学习好的,再加上时而再温故下linux下的知识,看看androi ... 
- Android开发学习之路--Android系统架构初探
		环境搭建好了,最简单的app也运行过了,那么app到底是怎么运行在手机上的,手机又到底怎么能运行这些应用,一堆的电子元器件最后可以运行这么美妙的界面,在此还是需要好好研究研究.这里从芯片及硬件模块-& ... 
- Android开发学习之路--MAC下Android Studio开发环境搭建
		自从毕业开始到现在还没有系统地学习android应用的开发,之前一直都是做些底层的驱动,以及linux上的c开发.虽然写过几个简单的app,也对android4.0.3的源代码做过部分的分析,也算入门 ... 
- Android开发学习之路-记一次CSDN公开课
		今天的CSDN公开课Android事件处理重难点快速掌握中老师讲到一个概念我觉得不正确. 原话是这样的:点击事件可以通过事件监听和回调两种方法实现. 我一听到之后我的表情是这样的: 这跟我学的看的都不 ... 
- Android开发学习之路-Android Studio开发小技巧
		上一次发过了一个介绍Studio的,这里再发一个补充下. 我们都知道,Android Studio的功能是非常强大的,也是很智能的.如果有人告诉你学Android开发要用命令行,你可以告诉他Andro ... 
随机推荐
- NodeJs之OS
			OS Node.js提供了一些基本的底层操作系统的模块OS. API var os = require('os'); console.log('[arch] 操作系统CPU架构'+os.arch()) ... 
- ASP.NET Core 之 Identity 入门(三)
			前言 在上一篇文章中,我们学习了 CookieAuthentication 中间件,本篇的话主要看一下 Identity 本身. 最早2005年 ASP.NET 2.0 的时候开始, Web 应用程序 ... 
- 开源:Taurus.MVC 框架
			为什么要创造Taurus.MVC: 记得被上一家公司忽悠去负责公司电商平台的时候,情况是这样的: 项目原版是外包给第三方的,使用:WebForm+NHibernate,代码不堪入目,Bug无限,经常点 ... 
- 重撸JS_1
			1.声明 用 var 或 let 声明的未赋初值的变量,值会被设定为undefined(译注:即未定义值,本身也是一个值) 试图访问一个未初始化的变量会导致一个 ReferenceError 异常被抛 ... 
- .NET平台开源项目速览(17)FluentConsole让你的控制台酷起来
			从该系列的第一篇文章 .NET平台开源项目速览(1)SharpConfig配置文件读写组件 开始,不知不觉已经到第17篇了.每一次我们都是介绍一个小巧甚至微不足道的.NET平台的开源软件,或者学习,或 ... 
- CSS 3学习——文本效果和@font-face
			文本效果 关于文本效果,这里仅仅记录得到大多数浏览器支持的几个属性,分别是: text-overflow text-shadow word-break word-wrap text-overflow ... 
- 代码的坏味道(17)——夸夸其谈未来性(Speculative Generality)
			坏味道--夸夸其谈未来性(Speculative Generality) 特征 存在未被使用的类.函数.字段或参数. 问题原因 有时,代码仅仅为了支持未来的特性而产生,然而却一直未实现.结果,代码变得 ... 
- PAT练习题目录
			点题号就能查看题解了,另外代码也放在了开源中国码云上: 甲级:代码集合:https://git.oschina.net/firstmiki/PAT-Advanced-Level-Practise 10 ... 
- MSYS2环境下编译X265
			HEVC(High Efficiency Video Coding),是一种新的视频压缩标准.可以替代H.264/ AVC编码,使得保持相同质量的情况下,体积减少40%左右.目前有多种实现版本,x26 ... 
- Kotlin的android扩展:对findViewById说再见(KAD 04)
			作者:Antonio Leiva 时间:Dec 12, 2016 原文链接:http://antonioleiva.com/kotlin-android-extensions/ 你也许已厌倦日复一日使 ... 
