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:

对于订阅者,有以下四种线程模式:

  1. POSTING:默认模式,订阅和事件发送在同一线程下进行
  2. MAIN:订阅在主线程下进行,可以直接修改UI
  3. BACKGROUND:如果事件发送在主线程,则订阅在子线程下进行,如果事件发送在子线程,则订阅也在该子线程中进行
  4. ASYNC:如果事件发送在主线程,则订阅在子线程下进行,如果事件发送在子线程,则订阅会在其他子线程中进行

设置订阅者线程很简单,只需要在注解中赋值即可,如:

     @Subscribe(threadMode = ThreadMode.MAIN)

③ 优先级

每个组件中可以有多个订阅方法,而我们可以对它们设置不同的优先级,设置的方法也很简单:

     @Subscribe(priority = 88)

默认的优先级为0,更高优先级的订阅方法会更先收到事件,而每个订阅方法都可以对事件进行终止,可以通过以下方法停止事件传递:

    EventBus.getDefault().cancelEventDelivery(messageEvent);

④ 自定义EventBus对象

通过getDefault方法获取的是一个EventBus默认的单例,而我们可以通过EventBus.Builder来构造一个自定义的EventBus对象。


明白了用法以后,我们分析源码也会更加简单。

Android开发学习之路-EventBus使用的更多相关文章

  1. Android开发学习之路-RecyclerView滑动删除和拖动排序

    Android开发学习之路-RecyclerView使用初探 Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析 Android开 ...

  2. Android开发学习之路--基于vitamio的视频播放器(二)

      终于把该忙的事情都忙得差不多了,接下来又可以开始good good study,day day up了.在Android开发学习之路–基于vitamio的视频播放器(一)中,主要讲了播放器的界面的 ...

  3. Android开发学习之路--Android Studio cmake编译ffmpeg

      最新的android studio2.2引入了cmake可以很好地实现ndk的编写.这里使用最新的方式,对于以前的android下的ndk编译什么的可以参考之前的文章:Android开发学习之路– ...

  4. Android开发学习之路--网络编程之xml、json

    一般网络数据通过http来get,post,那么其中的数据不可能杂乱无章,比如我要post一段数据,肯定是要有一定的格式,协议的.常用的就是xml和json了.在此先要搭建个简单的服务器吧,首先呢下载 ...

  5. Android开发学习之路--Activity之初体验

    环境也搭建好了,android系统也基本了解了,那么接下来就可以开始学习android开发了,相信这么学下去肯定可以把android开发学习好的,再加上时而再温故下linux下的知识,看看androi ...

  6. Android开发学习之路--Android系统架构初探

    环境搭建好了,最简单的app也运行过了,那么app到底是怎么运行在手机上的,手机又到底怎么能运行这些应用,一堆的电子元器件最后可以运行这么美妙的界面,在此还是需要好好研究研究.这里从芯片及硬件模块-& ...

  7. Android开发学习之路--MAC下Android Studio开发环境搭建

    自从毕业开始到现在还没有系统地学习android应用的开发,之前一直都是做些底层的驱动,以及linux上的c开发.虽然写过几个简单的app,也对android4.0.3的源代码做过部分的分析,也算入门 ...

  8. Android开发学习之路-记一次CSDN公开课

    今天的CSDN公开课Android事件处理重难点快速掌握中老师讲到一个概念我觉得不正确. 原话是这样的:点击事件可以通过事件监听和回调两种方法实现. 我一听到之后我的表情是这样的: 这跟我学的看的都不 ...

  9. Android开发学习之路-Android Studio开发小技巧

    上一次发过了一个介绍Studio的,这里再发一个补充下. 我们都知道,Android Studio的功能是非常强大的,也是很智能的.如果有人告诉你学Android开发要用命令行,你可以告诉他Andro ...

随机推荐

  1. NodeJs之OS

    OS Node.js提供了一些基本的底层操作系统的模块OS. API var os = require('os'); console.log('[arch] 操作系统CPU架构'+os.arch()) ...

  2. ASP.NET Core 之 Identity 入门(三)

    前言 在上一篇文章中,我们学习了 CookieAuthentication 中间件,本篇的话主要看一下 Identity 本身. 最早2005年 ASP.NET 2.0 的时候开始, Web 应用程序 ...

  3. 开源:Taurus.MVC 框架

    为什么要创造Taurus.MVC: 记得被上一家公司忽悠去负责公司电商平台的时候,情况是这样的: 项目原版是外包给第三方的,使用:WebForm+NHibernate,代码不堪入目,Bug无限,经常点 ...

  4. 重撸JS_1

    1.声明 用 var 或 let 声明的未赋初值的变量,值会被设定为undefined(译注:即未定义值,本身也是一个值) 试图访问一个未初始化的变量会导致一个 ReferenceError 异常被抛 ...

  5. .NET平台开源项目速览(17)FluentConsole让你的控制台酷起来

    从该系列的第一篇文章 .NET平台开源项目速览(1)SharpConfig配置文件读写组件 开始,不知不觉已经到第17篇了.每一次我们都是介绍一个小巧甚至微不足道的.NET平台的开源软件,或者学习,或 ...

  6. CSS 3学习——文本效果和@font-face

    文本效果 关于文本效果,这里仅仅记录得到大多数浏览器支持的几个属性,分别是: text-overflow text-shadow word-break word-wrap text-overflow ...

  7. 代码的坏味道(17)——夸夸其谈未来性(Speculative Generality)

    坏味道--夸夸其谈未来性(Speculative Generality) 特征 存在未被使用的类.函数.字段或参数. 问题原因 有时,代码仅仅为了支持未来的特性而产生,然而却一直未实现.结果,代码变得 ...

  8. PAT练习题目录

    点题号就能查看题解了,另外代码也放在了开源中国码云上: 甲级:代码集合:https://git.oschina.net/firstmiki/PAT-Advanced-Level-Practise 10 ...

  9. MSYS2环境下编译X265

    HEVC(High Efficiency Video Coding),是一种新的视频压缩标准.可以替代H.264/ AVC编码,使得保持相同质量的情况下,体积减少40%左右.目前有多种实现版本,x26 ...

  10. Kotlin的android扩展:对findViewById说再见(KAD 04)

    作者:Antonio Leiva 时间:Dec 12, 2016 原文链接:http://antonioleiva.com/kotlin-android-extensions/ 你也许已厌倦日复一日使 ...