来自:http://blog.csdn.net/bboyfeiyu/article/details/43450553

 AndroidEventBus

如果你不知道事件总线是什么,那么没有关系,下面我们先来看这么一个场景:

你是否在开发的过程中遇到过想在Activity-B中回调Activity-A中的某个函数,但Activity又不能手动创建对象来设置一个Listener什么的? 你是否想在某个Service中想更新Activity或者Fragment中的界面? 等等之类的组件之间的交互问题……

一经思考,你会发现Android中的Activity, Fragment, Service之间的交互是比较麻烦的,可能我们第一想到的是使用广播接收器来在它们之间进行交互。例如上述所说在Activity-B中发一个广播,在Activity-A中注册一个广播接收器来接受该广播。但使用广播接收器稍显麻烦,如果你要将一个实体类当做数据在组件之间传递,那么该实体类还得实现序列化接口,这个成本实在有点高啊!如下所示 :

<pre name="code" class="html"><pre name="code" class="java"><span style="color:#ff0000;"> // ActivityA中注册广播接收器</span><span style="color:#333333;">class ActivityA extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);registerReceiver(new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {User person = intent.getParcelableExtra("user") ;}}, new IntentFilter("my_action")) ;}// ...... }</span><span style="color:#ff0000;">// ActivityB中发布广播</span><span style="color:#333333;">class ActivityB extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Intent intent  = new Intent("my_action") ;intent.putExtra("user", new User("mr.simple")) ;sendBroadcast(intent);}// ...... }</span><span style="color:#ff0000;">  // 实体类实现序列化</span><span style="color:#333333;">class User implements Parcelable {String name ;public User(String aName) {name = aName ;}</span><span style="color:#ff0000;">       // 代码省略</span><span style="color:#333333;">@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(name);}}</span>

是不是有很麻烦的感觉! 
我们再来看一个示例,在开发过程中,我们经常要在子线程中做一些耗时操作,然后将结果更新到UI线程,除了AsyncTask之外,Thread加Handler是我们经常用的手段。我们看看如下示例:

<pre name="code" class="java"> class MyActivity extends Activity {Handler mHandler = new Handler () {public void handleMessage(android.os.Message msg) {if ( msg.what == 1 ) {User user = (User)msg.obj ;// do sth}};} ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// code ......new Thread(new Runnable() {public void run() {// do sthUser newUser = new User("simple") ;Message msg = mHandler.obtainMessage() ;msg.what = 1 ;msg.obj = newUser ;mHandler.sendMessage(msg) ;}}).start();}}

是不是又有相当麻烦的感觉!!! 
事件总线框架就是为了简化这些操作而出现的,并且降低组件之间的耦合而出现的,到底如何解决呢?咱们继续看下去吧。 
AndroidEventBus是一个Android平台轻量级的事件总线框架, 它简化了Activity、Fragment、Service等组件之间的交互,很大程度上降低了它们之间的耦合,使得我们的代码更加简洁,耦合性更低,提升我们的代码质量。

在往下看之前,你可以考虑这么一个场景,两个Fragment之间的通信你会怎么实现? 
按照Android官方给的建议的解决方法如下: Communicating with the Activity,思路就是Activity实现某个接口,然后在Fragment-A关联上Activity之后将Activity强转为接口类型,然后在某个时刻Fragment中回调这个接口,然后再从Activity中调用Fragment-B中方法。这个过程是不是有点复杂呢? 如果你也这么觉得,那也就是你继续看下去的理由了。

基本结构

 
AndroidEventBus类似于观察者模式,通过register函数将需要订阅事件的对象注册到事件总线中,然后根据@Subcriber注解来查找对象中的订阅方法,并且将这些订阅方法和订阅对象存储在map中。当用户在某个地方发布一个事件时,事件总线根据事件的参数类型和tag找到对应的订阅者对象,最后执行订阅者对象中的方法。这些订阅方法会执行在用户指定的线程模型中,比如mode=ThreadMode.ASYNC则表示该订阅方法执行在子线程中,更多细节请看下面的说明。

与greenrobot的EventBus的不同

  1. greenrobot的EventBus是一个非常流行的开源库,但是它在使用体验上并不友好,例如它的订阅函数必须以onEvent开头,并且如果需要指定该函数运行的线程则又要根据规则将函数名加上执行线程的模式名,这么说很难理解,比如我要将某个事件的接收函数执行在主线程,那么函数名必须为onEventMainThread。那如果我一个订阅者中有两个参数名相同,且都执行在主线程的接收函数呢? 这个时候似乎它就没法处理了。而且规定死了函数命名,那就不能很好的体现该函数的功能,也就是函数的自文档性。AndroidEventBus使用注解来标识接收函数,这样函数名不受限制,比如我可以把接收函数名写成updateUserInfo(Person info),这样就灵活得多了。
  2. 另一个不同就是AndroidEventBus增加了一个额外的tag来标识每个接收函数可接收的事件的tag,这类似于Broadcast中的action,比如每个Broadcast对应一个或者多个action,当你发广播时你得指定这个广播的action,然后对应的广播接收器才能收到.greenrobot的EventBus只是根据函数参数类型来标识这个函数是否可以接收某个事件,这样导致只要是参数类型相同,任何的事件它都可以接收到,这样的投递原则就很局限了。比如我有两个事件,一个添加用户的事件, 一个删除用户的事件,他们的参数类型都为User,那么greenrobot的EventBus大概是这样的:
<code class=" hljs cs" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">onEventMainThread</span>(User aUser) {<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// code </span>
}</code>

如果你有两个同参数类型的接收函数,并且都要执行在主线程,那如何命名呢 ? 即使你有两个符合要求的函数吧,那么我实际上是添加用户的事件,但是由于EventBus只根据事件参数类型来判断接收函数,因此会导致两个函数都会被执行。AndroidEventBus的策略是为每个事件添加一个tag,参数类型和tag共同标识一个事件的唯一性,这样就确保了事件的精确投递。 
这就是AndroidEventBus和greenrobot的EventBus的不同,但是由于本人对greenrobot的EventBus并不是很了解,很可能上述我所说的有误,如果是那样,欢迎您指出。

AndroidEventBus起初只是为了学习,但是在学习了EventBus的实现之后,发现它在使用上有些不便之处,我想既然我有这些感觉,应该也是有同感之人,在开发群里交流之后,发现确实有这样的情况。因此才将正式地AndroidEventBus以开源库的形式推出来,希望能够帮助到一些需要的人。当然,这个库的成长需要大家的支持与测试,欢迎大家发 pull request。

使用AndroidEventBus

你可以按照下面几个步骤来使用AndroidEventBus.

<pre name="code" class="java">1 注册事件接收对象
public class YourActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main_activity);// 注册对象EventBus.getDefault().register(this);}@Overrideprotected void onDestroy() {// 不要忘记注销!!!!EventBus.getDefault().unregister(this);super.onDestroy();}
}
2 通过Subscriber注解来标识事件接收对象中的接收方法
public class YourActivity extends Activity {// code ......// 接收方法,默认的tag,执行在UI线程@Subcriberprivate void updateUser(User user) {Log.e("", "### update user name = " + user.name);}// 含有my_tag,当用户post事件时,只有指定了"my_tag"的事件才会触发该函数,执行在UI线程@Subcriber(tag = "my_tag")private void updateUserWithTag(User user) {Log.e("", "### update user with my_tag, name = " + user.name);}// 含有my_tag,当用户post事件时,只有指定了"my_tag"的事件才会触发该函数,// post函数在哪个线程执行,该函数就执行在哪个线程    @Subcriber(tag = "my_tag", mode=ThreadMode.POST)private void updateUserWithMode(User user) {Log.e("", "### update user with my_tag, name = " + user.name);}// 含有my_tag,当用户post事件时,只有指定了"my_tag"的事件才会触发该函数,执行在一个独立的线程@Subcriber(tag = "my_tag", mode = ThreadMode.ASYNC)private void updateUserAsync(User user) {Log.e("", "### update user async , name = " + user.name + ", thread name = " + Thread.currentThread().getName());}
}
接收函数使用tag来标识可接收的事件类型,与BroadcastReceiver中指定action是一样的,这样可以精准的投递消息。mode可以指定目标函数执行在哪个线程,默认会执行在UI线程,方便用户更新UI。目标方法执行耗时操作时,可以设置mode为ASYNC,使之执行在子线程中。3 在其他组件,例如Activity, Fragment,Service中发布事件EventBus.getDefault().post(new User("android"));// post a event with tag, the tag is like broadcast's actionEventBus.getDefault().post(new User("mr.simple"), "my_tag");
发布事件之后,注册了该事件类型的对象就会接收到响应的事件.

Github链接

欢迎star和fork, AndroidEventBus框架 。

Android事件总线 ( AndroidEventBus ) 框架学习相关推荐

  1. Android事件总线 ( AndroidEventBus ) 开源库发布

    AndroidEventBus 如果你不知道事件总线是什么,那么没有关系,下面我们先来看这么一个场景: 你是否在开发的过程中遇到过想在Activity-B中回调Activity-A中的某个函数,但Ac ...

  2. Android事件总线设计(一)- EventBus初步学习

    Android事件总线设计(一) 我们通常在进行安卓设计的时候,不同的Activity,Fragment,Service等之间通讯一直是个不小的问题,用Intent以及Handler都觉得有一点麻烦, ...

  3. Android退出程序(三)——Android事件总线

    概述 当我们跟随时间的脚步向前挪动的时候,总能发现原来以前的自己做了一些愚蠢的事情.但,不见得以前就是不好的事情.我在以前的博客中写过两种关于Android中如何退出应用程序的方法.近日,我又发现了一 ...

  4. Android事件总线(一)EventBus3.0用法全解析

    相关文章 Android事件总线(一)EventBus3.0用法全解析 Android事件总线(二)EventBus3.0源码解析 Android事件总线(三)otto用法全解析 Android事件总 ...

  5. Android自定义事件总线,手写Android事件总线框架Eventbus(简易版)

    开篇废话 近期利用业余时间,跟着大神把Eventbus的框架学习了一下,在这里,记录一下这次学习的心得. EventBus是针一款对Android的发布/订阅事件总线.它可以让我们很轻松的实现在And ...

  6. Android事件总线还能怎么玩?

    作者简介:何红辉,Android工程师,现任职于友盟. 顾名思义,AndroidEventBus是一个Android平台的事件总线框架,它简化了Activity.Fragment.Service等组件 ...

  7. Android事件总线——EventBus的使用

    前言 首先我们来说下事件总线,它的作用:为了更简化并更高质量的在Activity,Fragment,Thread和Service等之间的通信,解决组件之间高耦合的同时仍能进行高效的通信. 什么是Eve ...

  8. Android事件总线

    Android中Activity.Service.Fragment之间的相互通信比较麻烦,主要有以下一些方法: (1)使用广播,发送者发出广播,接收者接收广播后进行处理: (2)使用Handler和M ...

  9. Android事件总线(四)源码解析otto

    前言 上一篇文章中讲到了otto的用法,这一篇我们来讲一下otto的源码.可能有人觉得otto过时了,但是通过源码我们学习的是高手设计otto时的设计理念,这种设计理念是不过时的. otto各个类的作 ...

最新文章

  1. Vue 2 | Part 4 v-bind绑定元素属性和样式
  2. 获取服务(getService)
  3. Citrix Netscaler负载均衡算法
  4. svn服务的安装与设置 .
  5. Vue.js - Day2
  6. CSS重新认识(一)
  7. web服务器 linux+apache+tomcat+mysql+jsp+php 整合安装
  8. 云计算相关的一些概念Baas、Saas、Iaas、Paas
  9. vue项目开发实战案例
  10. c语言24小时计时法转换为12小时,12时24时换算题(24小时和12小时换算方法)
  11. 循环经济升级推动产业升级发展建议
  12. Geforce 错误代码 ERROR CODE:0x0003问题方法
  13. 使用JS判断日期的有效性
  14. 计算机word论文,怎么用电脑Word写论文?
  15. 《程序员的数学1》读书笔记整理
  16. CSAPP 程序人生
  17. 大数据分析--用户画像
  18. 如何解决固定资产管理和盘点的难题?
  19. matlab里正负号怎么表示,正负号符号上下一起怎么输入?
  20. 良心整理:PDF工具合集

热门文章

  1. 小程序 globalData 详解
  2. 前三周学习Python的心得与感受
  3. Linux云计算架构师进阶班-Docker-K8s-Devops-Openstack
  4. A. 【UNR #2】积劳成疾
  5. Cesium基础-表面面积量算(依地形量算、依模型表面量算)
  6. Android十大开源框架
  7. 转盘式视觉筛选机及其图像识别系统
  8. 2022年度编程语言排行榜来啦,它凭什么能超过C语言,排名第一?
  9. 雨听|Mac使用“打印”将文件保存为本地PDF
  10. 使用jquery控制只能输入数字,并且关闭输入法