位置: 编程技术 - 正文
推荐整理分享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。
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 转载请保留说明!友情链接: 武汉网站建设