首先说说为什么要用它:
平常开发中免不了要进行各种aci或frgm之间的通信,其实aci之间相对还好,必竟可以通过intent方式,也不会觉得耦合性太强,但frgm之间就麻烦了,除了设置各种接口listener,将frgm做为参数传给另一个frgm外,确实没有其它能满足多种需求的方法。但这种监听器的方式,明显的感觉是这两个frgm是有关系的,代码跟逻辑上很容易混乱,无法成为优质的代码。
我趋向于写一个命令或消息,发出去就当事情完结了,因为对于发命令的这个对象来说,不关注执行过程,甚至于不关注执行结果(如果需要关注结果,就当新起一条线、做新一件事),执行方即使exception了,也影响不到自身。接口监听的方式显然没法做到这么洒脱。 所以有了EventBus,EventBus不能对app的性能产生多大影响,它也不是做这个事的,它存在意义是优化解耦代码、方便开发。
这样就牵扯到两种设计,前一种是监听者模式,后一种是发布、订阅模式。它们的主要区别在于监听者模式由被监听者直接调用订阅者的更新方法,强耦合,而另一种由发布者将消息事件发布给调度中心,由调度中心来分发事件给订阅者,发布者与订阅者之间是没有耦合关系的。

EventBus是greenrobot提供的android发布、订阅模式的实现,该作者另外还写了greendao,如果app中有对数据库大量操作的,需考虑性能问题的,可以去学习使用greendao,应该不会让你失望的。但我现在用的是使用更加方便的AndroidEventBus,它与原生EventBus的区别在于,它查找event监听方法时使用的是注解,而不是固定的字符串方法(打错一个字母都不行,编辑器也没有代码提示,易出错);它支持更精准的消息发送与接收,比如发送一个定位成功的消息,可以只发给对定位信息敏感的页面,而不是通知所有与定位有关的模块(EventBus也勉强支持,但是得写成类似这样,LocationEvent1,LocationEvent2,LocationEvent3····其实这些事件bean内部是完全一致的)。另外补充一句,AndroidEventBus的消息时间在150ms-1000ms之间,大多数维持在200ms左右,个人感觉能稳定在100ms会比较完美,EventBus的效率要高一些,但从使用上说我还是选择AndroidEventBus。

好了,废话一堆,下面开始简要讲解AndroidEventBus的使用与原理。

使用步骤

  1. aci或frgm oncreate时EventBus.getDefault().register(this); ondestory时EventBus.getDefault().unregister(this); this做为一个监听者的角色

  2. 编写作为携带数据的消息类,该类无规定,随意编写;编写任意方法名的消息类作为单一参数的方法,加注解@Subscriber(有代码提示,需要精准接收的使用@Subscriber(tag=”xx”))

  3. 上面两步是设置消息监听,该步是发消息的地方,调用EventBus.getDefault().post(消息类对象);

如果你在aci与frgm基类中统一register与unregister的方法,提供一个方法给子类来声明使用eventbus,使用上会更简便,我是这样做的

实现原理

为什么在发送消息post时,能将消息精准推送到监听方法处并执行该方法?
首先在register时,遍历监听类的所有方法,找到含Subscriber注解的且只有一个参数的方法,将参数的class与注解设置的tag组合成一个对象EventType,EventType做为一个key值,对应的value是一个含有相应监听者的CopyOnWriteArrayList,保存进map里。

/*** 查找订阅对象中的所有订阅函数,订阅函数的参数只能有一个.找到订阅函数之后构建Subscription存储到Map中* * @param subscriber 订阅对象* @return*/public void findSubcribeMethods(Object subscriber) {if (mSubcriberMap == null) {throw new NullPointerException("the mSubcriberMap is null. ");}Class<?> clazz = subscriber.getClass();// 查找类中符合要求的注册方法,直到Object类while (clazz != null && !isSystemCalss(clazz.getName())) {final Method[] allMethods = clazz.getDeclaredMethods();for (int i = 0; i < allMethods.length; i++) {Method method = allMethods[i];// 根据注解来解析函数Subscriber annotation = method.getAnnotation(Subscriber.class);if (annotation != null) {// 获取方法参数Class<?>[] paramsTypeClass = method.getParameterTypes();// 订阅函数只支持一个参数if (paramsTypeClass != null && paramsTypeClass.length == 1) {Class<?> paramType = convertType(paramsTypeClass[0]);EventType eventType = new EventType(paramType, annotation.tag());TargetMethod subscribeMethod = new TargetMethod(method, eventType,annotation.mode());subscibe(eventType, subscribeMethod, subscriber);}}} // end for// 获取父类,以继续查找父类中符合要求的方法clazz = clazz.getSuperclass();}}/*** 按照EventType存储订阅者列表,这里的EventType就是事件类型,一个事件对应0到多个订阅者.* * @param event 事件* @param method 订阅方法对象* @param subscriber 订阅者*/private void subscibe(EventType event, TargetMethod method, Object subscriber) {CopyOnWriteArrayList<Subscription> subscriptionLists = mSubcriberMap.get(event);if (subscriptionLists == null) {subscriptionLists = new CopyOnWriteArrayList<Subscription>();}Subscription newSubscription = new Subscription(subscriber, method);if (subscriptionLists.contains(newSubscription)) {return;}subscriptionLists.add(newSubscription);// 将事件类型key和订阅者信息存储到map中mSubcriberMap.put(event, subscriptionLists);}

在post时,还是根据EventType找到对应的监听者对象列表,然后invoke(反射执行)监听者的监听方法。

 /*** 处理单个事件* * @param eventType* @param aEvent*/private void handleEvent(EventType eventType, Object aEvent) {List<Subscription> subscriptions = mSubcriberMap.get(eventType);if (subscriptions == null) {return;}for (Subscription subscription : subscriptions) {final ThreadMode mode = subscription.threadMode;EventHandler eventHandler = getEventHandler(mode);// 处理事件eventHandler.handleEvent(subscription, aEvent);}}
handleEvent即是对监听方法反射执行subscription.targetMethod.invoke(subscription.subscriber.get(), event);

简单的说,根据消息类的class与注解tag,保存监听者对象的弱引用,在post时,再找到监听者对象,以反射方式执行相应的监听方法(反射解耦)。

再说下消息的运行线程:默认你的消息监听方法运行在UI线程中,你还可以通过注解mode指定其它两种方式

/*** 事件发布的线程模式枚举* * @author mrsimple*/
public enum ThreadMode {/*** 将事件执行在UI线程*/MAIN,/*** 在发布线程执行*/POST,/*** 将事件执行在一个子线程中*/ASYNC
}

需要关注的东西差不多就上面这些了,细节方面可以阅读AndroidEventBus的源代码,应该都比较容易读懂。

上面这些内容均是个人的总结与记忆,未参考任何文档,并不是一个非常完善的博文,供个人思路梳理与大家简要快速明白该事件库。

附上类图:

Android EventBus使用与思路总结相关推荐

  1. android EventBus的简单使用

    今天,简单讲讲Android里关于EventBus的使用. 这几天,由于面试的缘故,我听到了很多Android的流行框架,但是之前自己在公司做APP时并没有使用,所以没有了解.于是在网上查找了资料,学 ...

  2. android EventBus的简单使用

    今天,简单讲讲Android里关于EventBus的使用. 这几天,由于面试的缘故,我听到了很多Android的流行框架,但是之前自己在公司做APP时并没有使用,所以没有了解.于是在网上查找了资料,学 ...

  3. Android歌词秀设计思路(7)水到渠成

    我们用了6篇文章的篇幅做了铺垫,终于到了真正的应用程序了.这部分还是一如既往的简单. 有关应用的类有两个,一个是LiryicMain,一个是SelectFileActivity.都是差不多最低限度的内 ...

  4. Android歌词秀设计思路(8)后记

    写下这篇博文的时候,访问量的总数刚好过2000次,先自己庆祝一下. 做程序已经十八九年,但是写文章介绍自己的程序还是第一次.是实话这件事的难度超出了我的预想. 一个是篇幅长,原先以为很简单的一个程序, ...

  5. Android EventBus

    Android EventBus 1.Eventbus工作流程 2.导入EventBus库 implementation 'org.greenrobot:eventbus:3.1.1' 3.角色分配 ...

  6. Android -- EventBus使用

    EventBus EventBus是一个Android端优化的publish/subscribe消息总线,简化了应用程序内各组件间.组件与后台线程间的通信.比如请求网络,等网络返回时通过Handler ...

  7. Android EventBus 的使用

    1.EventBus 简介 EventBus是一种用于Android的事件发布-订阅总线,由GreenRobot开发,Gihub地址是:EventBus.它简化了应用程序内各个组件之间进行通信的复杂度 ...

  8. Android EventBus使用(不含源码解析)

    官方文档:https://github.com/greenrobot/EventBus simplifies the communication between components decouple ...

  9. Android 插件框架实现思路及原理

    插件框架实现思路及原理 一.技术可行性 a) apk的安装处理流程 i. apk会copy到/data/app: ii. 解压apk中的class.dex,并对其进行优化,获得odex(即JIT).最 ...

最新文章

  1. linux 内核round-robin scheduler代码,LINUX源代码阅读报告
  2. 深度学习原理—代码分析线性分类与神经网络分类的区别
  3. 将数据到处到Excel
  4. com.mysql.jdbc.PacketTooBigException: Packet for query is too large
  5. [转]毕业五年决定你的命运-----值得所有不甘平庸的人看看
  6. sun的没落是悲还是喜?
  7. ci框架 反向代理配置_《网站建设》Nginx配置反向代理
  8. 机器学习-Logistic回归原理及实战
  9. 【计算机组成原理】定点乘法运算之原码两位乘法
  10. 入行||转行软件测试?写给迷惘的你
  11. 关于hankcs库的自然语言处理
  12. 测试方法之JUnit单元测试
  13. QAM调制原理_QAM调制:4/5G中各种调制方式基础,均由两条正弦波变化并勾勒出...
  14. android 电源管理驱动
  15. 你不会因为实施了Scrum而变敏捷
  16. 【毕业设计】基于单片机的智能鱼缸系统设计与实现 - 嵌入式 物联网 stm32 c51
  17. 蓝狐笔记:DeFi现在仍处在初级阶段 | FBEC 2020特别策划
  18. 免费获取全球生物量密度1km网格tif数据(GEDI L4B Gridded Aboveground Biomass Density, Version 2)
  19. win10 和ubuntu双系统设置启动顺序和时间
  20. ArcGIS地图抽稀

热门文章

  1. 为什么不可以使用哈曼顿距离_哈曼卡顿音乐琉璃1代2代评测,不但抓耳,还让你视线也难离开...
  2. CentOS 8中安装Docker出现和Podman冲突
  3. 怎么设置表格根据窗口自动调整_Word排版技巧之表格美化,你值得拥有!
  4. Pdf怎么转换excel表格,职场人士必备技能
  5. 第03课:Spring Boot 启动原理
  6. 第55件事 产品疯传的7个基本原则
  7. WCF NetTcpBinding Transport安全模式(6) ClientCredentialType证书验证模式---- PeerTrust验证模式...
  8. U-boot中常用参数设定及常用宏的解释和说明
  9. (三)Sass和Compass--制作精灵图片
  10. JDK5 新特性之 可变参数的方法(2)---asList