位置: 编程技术 - 正文

Android之EventBus概述及源码解析(雷惊风)(android observer)

编辑:rootadmin

推荐整理分享Android之EventBus概述及源码解析(雷惊风)(android observer),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:android eventbus优缺点,android observer,android概述,android概述,android:accessibilityeventtypes,android:cursorvisible,android event,android:accessibilityeventtypes,内容如对您有帮助,希望把文章链接给更多的朋友!

前段时间公司在项目中用到了Android三方开源库—EventBus。一直没时间总结,只能抽周末点时间总结一下,其中也借鉴了一些前辈的智慧。好了废话不多少,开始吧... ...

一、简单介绍。

在Android中当我们做完一件事在去通知其他模块进行后续任务的时候(下载完成,更新界面;评论成功,更新其他页面评论显示或条数增加等等),也有很多方法,比如Handler、BroadCastReceiver、Interface回调等,其实也是很好用的,但是他们在一定程度上是存在耦合度的,同时,用起来有时候也有点小复杂,EventBus的出现使我们完成同样的功能节省了不少时间,它代码简单,使用方便,充分降低了任务已经完成者与任务后续进行者之间的耦合度,所有的事件都交由EventBus这个类来管理。

二、涉及到的模块。 想通过Eventbus完成事件传递,至少要涉及3个部分,订阅者、发布者、事件,下边逐个简单介绍。 1.订阅者订阅者就是我们任务完成后,需要更新页面的那些类,我们的每一个订阅者都可以订阅一个或多个事件对象,当发布者发布对应事件后,EventBus会查找所有订阅了本事件的所有订阅者,并执行订阅者操作类中相应的OnEvent*(Object)方法,完成对应操作。 2.发布者发布者就是我们在完成任务后要通知订阅者更新最新信息的那个模块。简单来说,就是就是发布某个事件的对象,当发布者完成特定任务后,发布事件,事件总线EventBus通过事件获取对应的订阅者列表,循环执行订阅者中对应的OnEvent*(Object)事件响应函数。

发布事件方法:EventBus.getDefault().post(EventOb);

3.事件 就是一个我们自己定义的对象。可以携带一些处理后的信息。分为普通事件和 Sticky事件,相对于一般事件,Sticky事件不同之处在于,当事件发布后,再有订阅者开始订阅该类型事件,依然能收到该类型事件最近一个 Sticky事件。三、用到的方法及作用。 1.EventBus.getDefault().register(this);

注册当前类到事件总线EventBus。This参数为当前activity的上下文对象。写在订阅者对象中。

2.EventBus.getDefault().post(new EventOB());

发布一个EventOB事件到事件总线EventBus中,EventOB为发布的事件类型,也就是一个对象。

3.Public void onEvent/onEvenMainThread /BackgroundThread/Async(){};

当发布者发布事件后,EventBus找到订阅者后通过订阅者的 ThreadMode名称类型在相应线程执行内部代码。ThreadMode共四种:

&#;①PostThread:直接调用订阅者的事件响应函数;

②MainThread 如果发布线程就是主线程,则直接调用订阅者的事件响应函数,否则通过主线程的 Handler发送消息在主线程中处理,调用订阅者的事件响应函数;

③BackgroundThread 如果发布线程是主线程,则启动异步线程去处理,否则直接直接调用订阅者的事件响应函数;

④Async ,启动异步线程去处理,调用订阅者的事件响应函数。

4.EventBus.getDefault().unRegister(this);

取消当前类订阅。

四、源码分析。 好了,通过前边的大致介绍,相信大家对EventBus已经有了一个大致的了解,从现在开始进入对EventBus更深入的了解吧,让我们看看它的内部实现原理。 1.订阅流程。EventBus.getDefault().register(this); EventBus.getDefault()对于defaultInstance的双重判断,防止线程并发访问产生多个对象。 首先看一下它的功能流程图: 废话不多少,上源码: 我们可以看上边代码,不管你采用哪中注册方式,其实它最终都调用了三个参数的构造方法,好吧,我们对他进行一下解剖,呵呵: 首先,我们看一下三个参数,subscriber:我们注册时传递过来的acticity上下文对象;sticky:是否粘性;priority:优先级设置,EventBus会根据我们设置的优先级进行排序。 register方法中分为两部分: 1.通过subscriberMethodFinder得到了subscriberMethods;(subscriberMethodFinder订阅者响应函数信息存储和查找类。) 2.for循环遍历subscriberMethods。好,接着往下走,看一下到现在整个注册流程就完了,总结一下:register 函数中会先根据订阅者类名去 subscriberMethodFinder 中查找当前订阅者所有事件响应函数,然后循环每一个事件响应函数,依次执行下面的 subscribe 函数:首先扫描了所有的方法,

subscribe 函数分三步

第一步:通过 subscriptionsByEventType 得到该事件类型所有订阅者信息队列,根据优先级将当前订阅者信息插入到订阅者队列 subscriptionsByEventType 中;

第二步:在 typesBySubscriber 中得到当前订阅者订阅的所有事件队列,将此事件保存到队列 typesBySubscriber 中,用于后续取消订阅;

第三步:检查这个事件是否是 Sticky 事件,如果是则从 stickyEvents 事件保存队列中取出该事件类型最后一个事件发送给当前订阅者。

擦,下午1点了,还没吃饭,算了,弄完再说吧。接着来...2.发布流程。EventBus.getDefault().Post(new EventOB());先看流程图 上源码:currentPostingThreadState是一个ThreadLocal类型的,它的作用大家可以去看一下,里面存储了PostingThreadState;PostingThreadState包含了一个eventQueue和一些标志位。下面接着看PostSingleEvent方法, 如果在支持继承的前提下,得到了event对应的每种类型,通过for循环去调用PostSingleEventForEventType方法,我们看看她在里面做了哪些操作; 可以看到,在这里他通过event从保存了我们所有信息的subscriptionsByEventType中得到我们所有订阅当前事件的所有对象,并for循环对每一个对象调用postToSbuscription()方法,其中赋&#;了部分postingState参数;下面继续深究postToSubscription()方法;我们传入了订阅了当前事件的对象、事件本身、发布是否在主线程中。看invokeSubscriber方法: 可以看到在invokeSubscriber()方法中用到了反射方式调用订阅者中对应的onEvent*()方法。其实mainThreadPoster、BackgroundThread、asyncPoster中最后都是调用了这个方法来完成对应方法的调用。 case MainThread: 首先去判断当前如果是UI线程,则直接调用;否则: mainThreadPoster.enqueue(subscription, event);把当前的方法加入到队列,然后直接通过handler去发送一个消息,在handler的handleMessage中,去执行我们的方法。说白了就是通过Handler去发送消息,然后执行的。 case BackgroundThread: 如果当前非UI线程,则直接调用;如果是UI线程,则将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用executorService = Executors.newCachedThreadPool();。 case Async:将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用;线程池与BackgroundThread用的是同一个。 BackgroundThread中的任务,一个接着一个去调用,中间使用了一个布尔型变量handlerActive进行的控制。Async则会动态控制并发。 好了,我们的发布就介绍到这里。 3.另一种发布。postSticky(Object event); 介绍了register和post;大家获取还能想到一个词sticky,在register中,如何sticky为true,会去stickyEvents去查找事件,然后立即去post;那么这个stickyEvents何时进行保存事件呢?其实evevntbus中,除了post发布事件,还有一个方法也可以: 这个方法就是再调用post方法前把方法存储到stickyEvents中去了。 4.注销订阅EventBus.getDefault().unregister(this); 看源码: 首先从typesBySubscriber中通过上下文对象得到当前类订阅的所有事件,再for循环每一个事件调用unubscribeByEventType(subscriber, eventType);循环完以后从typesBySubscriber中删除保存的对象。看unubscribeByEventType()方法:

在这里我们再次看到了subscriptionsByEventType,通过eventType得到订阅了本事件的所有类集合,及subscriptions。在从subscriptions得到每一个循环对比,如果是当前类,则从subscriptions中将其删除掉。完成取消注册订阅。好了源码就跟大家介绍到这里。下边看一下辅助方面的东西。

五、EventBus主要成员变量含义

1. defaultInstance 默认的 EventBus实例,根据 EventBus.getDefault() 函数得到。

2. DEFAULT_BUILDER 默认的 EventBus Builder。

3. eventTypesCache 事件对应类型及其父类和实现的接口的缓存,以 eventType为 key,元素为 Object的 ArrayList为 Value,Object对象为 eventType的父类或接口。 4. subscriptionsByEventType 事件订阅者的保存队列,以 eventType为 key,元素为 Subscription 的 ArrayList 为 Value,其中 Subscription 为订阅者信息,由 subscriber, subscriberMethod, priority 构成。

5. typesBySubscriber 订阅者订阅的事件的保存队列,以 subscriber为 key,元素为 eventType的 ArrayList为 Value。

6. stickyEvents Sticky事件保存队列,以 eventType为 key,event为元素,由此可以看出对于同一个 eventType最多只会有一个 event存在。

7. currentPostingThreadState 当前线程的 post信息,包括事件队列、是否正在分发中、是否在主线程、订阅者信息、事件实例、是否取消。

8. mainThreadPoster 、 backgroundPoster 、 asyncPoster 事件主线程处理者、事件 Background 处理者、事件异步处理者。

9. subscriberMethodFinder 订阅者响应函数信息存储和查找类。

. executorService 异步和 BackGround处理方式的线程池。

. throwSubscriberException 当调用事件处理函数异常时是否抛出异常,默认为 false,建议通过

EventBus.builder().throwSubscriberException(true).installDefaultEventBus()打开。

. logSubscriberExceptions 当调用事件处理函数异常时是否打印异常信息,默认为 true。

. logNoSubscriberMessages 当没有订阅者订阅该事件时是否打印日志,默认为 true。

. sendSubscriberExceptionEvent 当调用事件处理函数异常时是否发送 SubscriberExceptionEvent事件,若此开关打开,订阅者可通过

. sendNoSubscriberEvent 当没有事件处理函数对事件处理时是否发送NoSubscriber Event事件,若此开关打开,订阅者可通过

. eventInheritance 是否支持事件继承,默认为 true。

六、涉及到的类介绍1.EventBusBuilder.java

跟一般 Builder类&#;,用于在需要设置参数过多时构造 EventBus。包含的属性也是 EventBus的一些设置参数,意义见 4.2.1 EventBus.java 的介绍,build函数用于新建 EventBus 对象,installDefaultEventBus函数将当前设置应用于 Default EventBus。

Android之EventBus概述及源码解析(雷惊风)(android observer)

2.SubscriberMethodFinder.java

订阅者响应函数信息存储和查找类,由 HashMap缓存,以 ${subscriberClassName}为 key,SubscriberMethod对象为元素的 ArrayList为 value。findSubscriberMethods函数用于查找订阅者响应函数,如果不在缓存中,则遍历自己的每个函数并递归父类查找,查找成功后保存到缓存中。

3.SubscoberMethod.java

订阅者事件响应函数信息,包括响应方法、线程 Mode、事件类型以及一个用来比较 SubscriberMethod是否相等的特征&#; methodString共四个变量,其中 methodString为${methodClassNmae}#${methodName}(${eventTypeClassName}。

4.Subscription.java

订阅者信息,包括 subscriber对象、事件响应方法 SubscriberMethod、优先级 priority.

5.HandlerPoster.java

事件主线程处理,对应 ThreadMode.MainThread 。继承自 Handler,enqueue函数将事件放到队列中,并利用 handler 发送message,handleMessage函数从队列中取事件,invoke事件响应函数处理。

6.AsyncPoster.java

事件异步线程处理,对应 ThreadMode.Async ,继承自 Runnable。enqueue函数将事件放到队列中,并调用线程池执行当前任务,在 run 函数从队列中取事件,invoke事件响应函数处理。

7.BackgroundPoster.java

事件 Background处理,对应 ThreadMode.BackgroundThread ,继承自 Runnable。enqueue函数将事件放到队列中,并调用线程池执行当前任务,在 run函数从队列中取事件,invoke事件响应函数处理,与 AsyncPoster.java不同的是这里会循环等待 run,尚未想清楚原因。

8.PendingPost.java

订阅者和事件信息实体类,并含有同一队列中指向下一个对象的指针。通过缓存存储不用的对象,减少下次创建的性能消耗。

9.PendingPostQueue.java

通过 head和 tail指针维护一个 PendingPost 队列。HandlerPoster、AsyncPoster、BackgroundPoster都包含一个此队列实例,表示各自的订阅者及事件信息队列,在事件到来时进入队列,处理时从队列中取出一个元素进行处理。

.SubscriberExceptionEvent.java

当调用事件处理函数异常时发送的 EventBus内部自定义事件,通过 post发送,订阅者可自行订阅这类事件进行处理。

.NoSubscriberEvent.java

当没有事件处理函数对事件处理时发送的EventBus内部自定义事件,通过 post发送,订阅者可自行订阅这类事件进行处理。

.EventBusException.java

封装于RuntimeException之上的 Exception,只是覆盖构造函数,相当于一个标记,标记是属于 EventBus的 Exception。

.4.2. ThreadMode.java

线程 Mode枚举类,表示事件响应函数执行线程信息,包括ThreadMode.PostThread 、 ThreadMode.MainThread 、ThreadMode.BackgroundThread 、 ThreadMode.Async 四种。好了,刚刚开始在CSDN上边发表文章,还不太会用,不好意思,有些地方可能说的不是很清楚,请大家谅解。总算完了,也两点半了,收拾收拾去吃饭了,擦,还真饿了!!刚刚创建了,希望能共同学习,非诚勿扰!

版权声明:本文为博主原创文章,未经博主允许不得转载。

Android Camera探究之路——起步 AndroidCamera探究之路——起步Camera在手机中有着举足轻重的地位,不管是二维码还是照片、识别,都离不开摄像头,本文将对Android中的Camera进行全面解析

Android自定义View圆环带文字进度条 项目原型图中有这样的一种进度条由于懒得找第三方(找到的不一定合用,有找的时间自己也就写了一个)自定义所需要的属性?xmlversion="1.0"encoding="utf-8

Android Socket 通信实例...【Pnoker】 这几天一直在学习Java套接字,昨天做了个小实验,发现仅简单的把JavaSocket通信的代码放在Android上是会报错的,而且问题还很大,于是乎,我就搜集了

标签: android observer

本文链接地址:https://www.jiuchutong.com/biancheng/374361.html 转载请保留说明!

上一篇:android hander如何避免内存泄露(android的handler)

下一篇:Android Camera探究之路——起步(android camera preview)

  • 公司房产税怎么做分录
  • 应税消费品是什么意思
  • 累计个税是每年累计吗
  • 当期可抵扣进项税额加计5%抵减应纳税额
  • 先报个税还是先报增值税,有影响吗?
  • 经营所得税投资者减除费用
  • 回退税款所属期具体条件是
  • 个体户电子发票怎么作废
  • 善意接受虚开发票只能自认倒霉么
  • 企业房产税怎么申报缴纳
  • 政府补贴装修费怎么算
  • 公司购买的五金工具报销怎么做
  • 未使用的固定资产提不提折旧
  • 工程维修费用怎么入账
  • 产品成本的归集和分配是什么意思
  • 印花税的计税金额
  • 本地开的住宿费可以退吗
  • 个人开具工程款发票
  • 小配件出口怎么报关
  • 长期股权投资账务处理
  • 成品油发票应该怎么冲红?
  • 归还银行贷款怎么做分录
  • 免抵退税额如何计算
  • 工资退税手续需要多久
  • 所得税费用属于损失吗
  • 进项税加计抵扣分录
  • 法律的禁止性规定
  • 机动车检测工作
  • 内外账合并步骤
  • 如何编制固定资产折旧计算表
  • 企业重组特殊性处理通俗理解
  • 四种存款账户的定义
  • 留底税额怎么分录
  • 企业不得抵扣进项税
  • 发票跨年作废很麻烦吗
  • vue3项目打包
  • from origin ‘null‘ has been blocked by CORS policy: Cross origin requests are only supported for ...
  • 哪些费用需要计提,哪些不需要
  • 怎么计算应缴所得税
  • 企业废品处理管理办法
  • thinkphp案例
  • 开发成本属于什么类型科目
  • html里面有什么
  • thinkphp函数有哪些
  • phpcms使用教程
  • sqlyog
  • 给客户的回扣如何做账
  • 零申报企业所得税的资产总额怎么填写
  • 电子钥匙报税
  • 企业有哪些固定资产
  • 非独立核算增值税汇总缴纳吗
  • 预缴增值税附加税需要计提吗
  • 研发项目会计分录
  • 普通发票开具红字发票后发票联怎么处理?
  • 农产品加计扣除1%账务处理
  • 什么时候计提增值税发票
  • 物业公司预收的物业费怎么做账
  • 企业之间的往来款要1900万要交多少税
  • 收不回来的应收账款会计分录
  • 汇兑损益的账务处
  • 国际货运代理公司税率为啥是免税
  • Win7旗舰版系统文件名称
  • win8系统开机直接进入桌面
  • grub rescue修复引导找不到grub
  • win7鼠标右键没有压缩文件
  • jinjia.exe进程
  • 腾讯linux服务器
  • 如何重设苹果手机的ID密码
  • linux禁止root用户远程登录
  • WIN10系统安装.net报错0x80072f8F
  • css nowrap
  • jQuery中的select操作详解
  • 每天一篇小练笔30字
  • CLASS_CONFUSION JS混淆 全源码
  • javascript面向对象编程 PDF
  • 怎么检查手机网络
  • 吉林省国家税务局官网
  • 所有的酒店真的有摄像头吗
  • 土地增值税分期清算条件?
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设