EventBus的使用与深入学习
2016-05-06 09:17
387 查看
注意:以下分析都是基于EventBus 3.0x
转载请注明出处:/article/7733231.html
传统的Android组件之间的通信方式有:Activity之间使用Intent;Service向Activity发送broadcast;Fragment和Activity之间相互持有对方的引用(随后可以调用对方的相关方法进行事件传递)。传统的事件传递的问题在于:通信方式没有实现解耦,是硬编码在组件中的。组件一旦发生修改,对应的通信方式就需要跟着修改。其实不管什么场景下,我们最好能够使得自己编写的代码最大限度的解耦,这是一个很好的习惯,避免无用功,提高代码利用率。
使用EventBus的建议:
并不建议将应用中所有的事件都通过EventBus进行发送,尤其对于一对一的组件之间通信,建议不要使用EventBus。EventBus的使用场景更像是一种广播,当我们向EventBus发送一个事件,则该事件将会传递给多个该事件的订阅者,比如Service向Activities发送事件。跟LoacalBroadCast有点近似
在Activity和Fragment中使用EventBus时,要注意在组件的生命周期开始时registered EventBus,在生命周期结束时unregistered EventBus。否则容易导致OOM;
使用EventBus的好处在于:
简化组件之间的通信方式
让业务代码更加简洁(但是需要配合相应注解进行使用)
可以指定事件处理方法的执行线程,和订阅者的优先级(跟广播类似)
足够的稳定,已经被很多Android应用使用,你绝对不是第一个吃螃蟹的人
EventBus实现了解耦,事件的创建和分发由EventBus管理,工作在一个单独的线程。EventBus的工作原理如下图:
二、定义事件
三、注册EventBus
四、发布事件
五、创建事件处理方法
此处的threadMode = ThreadMode.MAIN表明下面的事件处理方法在 ThreadMode.MAIN线程中执行,默认会在EventBus的工作线程中执行(发送post事件方法所在的线程)。
ThreadMode.POSTING:在和发送事件相同的线程中执行。默认的线程模式
ThreadMode.MAIN:Android的UI线程中执行。
ThreadMode.BACKGROUND:交给EventBus的一条幕后线程去执行,注意EventBus中只有一个这样的幕后线程,所以的异步方法会在这条线程中顺序执行。要求事件处理方法不要耗时太长!
ThreadMode.ASYNC:在一个单独的线程中执行,总是和发送事件的线程以及UI线程相隔离。将每个这样的事件处理方法扔到一个线程池申请一条线程进行处理。对于网络请求等可以使用这种模式!
EventBus内部存储有哪些域,我们通过getDefault方法获取到的是不是它的一个单例?
EventBus的unregister和register方法内部是怎样的业务逻辑。是简单的将该对象添加一个集合,然后像Retrofit那样为每个使用了@Susbcribe标注的Method创建一个ServiceMethod?
EventBus的post方法内部的业务逻辑、是去遍历调用注册了该事件的方法来处理该事件?如何快速的找到注册了该事件的方法(Map)?
使用了@Subscribe(threadMode = ThreadMode.MAIN)标注的方法为何会在指定的线程中执行?
接着我们看看使用getDefault方法得到的EventBus对象
getDefault()@EventBus.class
一个很经典的单例模式,调用EventBus的构造器创建EventBus对象;
EventBus()@EventBus.class
EventBusBuilder.class
Fields:
到此为止我们分析了调用getDefault方法得到的EventBus对象;
该对象存储有如下两个集合
Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
以事件类型为键,每个事件对应一个Subscription对象的集合。EventBus一旦收到一个事件就会遍历它对应的Subscription集合,将该事件推送给Subscription处理。对于Subscription对象的如何构建和使用后文将会给出。
Map<Object, List<Class<?>>> typesBySubscriber;
以事件订阅者为键(事件订阅者就是register方法的参数),每个订阅者对应一组它能接收的事件类型集合。一旦订阅者和EventBus解除注册,即调用unregister方法时,EventBus就会取出订阅者对应的所有事件类型,去subscriptionsByEventType中移除该事件对应的Subscription对象集合中的和订阅者关联的Subscription。
该对象存储有如下四个执行器
ExecutorService executorService = Executors.newCachedThreadPool();
是一个线程池,ThreadPoolExecutor(0.Integer.MAX_VALUE,....)
HandlerPoster mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
对应ThreadMode.MAIN模式,是一个继承Handler的类;事件的推送在其HandlerMessage方法中执行
private final BackgroundPoster backgroundPoster;
对应ThreadMode.BACKGROUND模式,是一个实现了Runnable方法的类;事件的推送就是将自己扔给executorService,如果当前对象已经在执行了,则只是将事件放入到BackgroundPoster中的一个队列中;否则将自己交给线程池执行其run方法。BackgroundPoster对象的run方法会一直遍历这个队列,直到队列没有数据则退出run方法。
private final AsyncPoster asyncPoster;
对应ThreadMode.ASYNC模式,是一个实现了Runnable方法的类;相对于BackgroundPoster这里一旦有事件需要分发则立即将自己扔给线程池,而不是直接将事件扔给队列就完了。
本节后面还会对上述这些执行器进行详细的说明。下面我们先来分析下EventBus的register方法。
register()@EventBus.class
1、从subscriberMethodFinder中获取subscriberClass (注意这里是Class对象不是Obejct对象) 对应的使用了@Subscribe标注的方法集合;大体流程:从缓存区中尝试获取,获取不到再利用FindSubscriber中的FindState去解析subscriberclass对象。SubscriberMethodFinder.findSubscriberMethods方法参考后面的SubscriberMethodFinder.class部分的介绍。实在憋不住就先跳到那里看看如何实现-->
2、遍历集合List<SubscriberMethod>中的每个元素,调用subscribe方法处理。SubscriberMethod是对使用了@Subscribe标注的方法的解析,该对象包含有方法(Method)、方法参数类型(Type)、线程模式(ThreadMode)、订阅的优先级。SubscriberMethod与Retrofit为每个采用了标注的方法创建ServiceMethod对象的做法类似。
下面我们看看subscribe方法底层实现。
subscribe()@EventBus.class
1、获取方法参数类型;注意:使用@Subscribe标注的方法有且仅有一个参数
2、利用订阅者对象及其事件处理方法构建一个Subscription对象,该对象存储有Object、SubscriberMethod对象,在本节的最后也贴上了Subscription.class的源码
3、从subscriptionsByEventType集合中获取当前事件对应的Subscription对象集合; 如果得到的集合为空则创建一个这样的集合,并将刚创建的Subscription对象添加进subscriptionsByEventType集合中;如果得到的集合不为空且刚创建的Subscription对象已经存在该集合中则抛出异常,即同一个对象不能注册两次!
4、将第二步创建的Subscription对象按照优先级存入Subscription对象集合中,该集合中的元素都是按照优先级从高到低存放.
5、以subscriber对象为键,从typesBySubscriber获取该对象对应的接收事件类型集合,没有则创建一个这样的集合,然后当前事件类型添加到该集合中,最后将整个集合添加进typesBySubscriber集合中;有则直接添加到接收事件类型集合中;
6、该值默认为false,除非在注册事件方法时使用了如下的标注@Subscribe(sticky = true);那么就会执行到这里。stickyEvent也是EventBus3.0的一大特点,该类事件一旦发送给EventBus,那么EventBus就会将它存入Map<Class<?>,
Object> stickyEvents集合中,key事件类型,value事件实例;每个类型事件对应最新的实例。当订阅对象的某个事件处理方法使用了@Subscribe(sticky = true)标注,EventBus一旦对订阅者完成了注册任务之后,立即将stickyEvents集合中的匹配事件发送给该事件处理进行处理!具体实现就是这里!stickyEvents配套使用的向EventBus发送事件的方法为postSticky,具体内容如下:
同时将stickyEvents中某个类型的事件手动删除的方法为:
接着看看unregister方法内部逻辑
unregister()@EventBus.class
1、从typesBySubscriber获取该对象接收的事件类型集合;
2、对得到的接收事件类型集合中的每个事件类型调用unsubscribeByEventType进行处理;跟着我们就分析该方法
3、该对象从typesBySubscriber集合中移除;
unsubscribeByEventType()@EventBus.class
1、从subscriptionsByEventType集合中获取该事件类型对应的Subscription集合
2、如果集合中的元素——Subscription的subscriber域等于目标subscriber,则将该Subscription从subscriptionsByEventType集合中移除出去;
分析完了register和unregister方法我们接着分析EventBus的最后一个方法——post方法!
post()@EventBus.class
1、获取当前线程对应的一个PostingThreadState()对象;回顾一下我们在EventBus中创建的如下域
ThreadLocal类型的特点是当调用currentPostingThreadState.get()方法的时候,会返回当前线程所持有的一个 PostingThreadState对象;在不同的线程中执行同样一行代码它们得到的对象是不同的。PostingThreadState也很简单,就是定义了一堆数据,没有任何方法。下面就是它的所有源码
2、向PostingThreadState的事件队列中添加一个事件
3、从PostingThreadState的事件队列——eventQueue中移出一个事件,并调用postSingleEvent方法进行派送
postSingleEvent()@EventBus.class
1、eventInheritance该标志位默认为true,表示只要 满足订阅事件是该事件的父类或者实现了该事件同样接口或接口父类 中的任何一个条件的订阅者都会来处理该事件。
2、该方法从名字来看就是获取eventClass的所有父类往上都能追溯到Object、和所有实现的接口、以及接口父类;EventBus进行了优化采用了缓存机制Map<Class<?>, List<Class<?>>> eventTypesCache。
3、将eventClass所有的关联类都通过postSingleEventForEventType进行推送;下面跟着就会分析该方法
4、如果该事件没有推送成功,即没有事件处理器来处理这类事件;系统会尝试发送一个post(new NoSubscriberEvent(this, event))事件
postSingleEventForEventType()@EventBus.class
1、获取原始事件的关联类对应的所有Subscription对象
2、将上述Subscription对象集合进行遍历,使用postToSubscription方法处理原始事件
postToSubscription()@EventBus.class
1、POSTING直接在当前线程执行,调用invokeSubscriber方法
2、MAIN即UI线程执行:如果当前线程就是UI线程则直接调用invokeSubscriber方法,否则将任务交给mainThreadPoster——HandlerPoster(this, Looper.getMainLooper(), 10)对象异步执行,最终会调用invokeSubscriber(PendingPost
pendingPost)方法;后面还会对HandlerPoster类型进行分析,参考HandlerPoster.class源码部分
3、BACKGROUND背景线程执行:其实就在非UI线程中执行,如果当前线程是非UI线程则直接调用invokeSubscriber方法,否则将任务交给backgroundPoster——BackgroundPoster(this)对象异步执行,最终会调用invokeSubscriber(PendingPost pendingPost)方法;后面还会对BackgroundPoster进行分析,参考BackgroundPoster.class源码部分
4、ASYNC:将任务交给 asyncPoster—— AsyncPoster(this)对象异步执行,最终会调用invokeSubscriber(PendingPost pendingPost)方法;后面还会对AsyncPoster进行分析,参考AsyncPoster.class源码部分
invokeSubscriber()@EventBus.class
1、调用subscriber的对应方法,java反射的知识;
invokeSubscriber()@EventBus.class
1、该方法与前面的方法类似,只是接受参数不同而已,内部还是会调用 invokeSubscriber(subscription, event)方法!
到此为止我们对于EventBus的注册、注销、发送事件、接收事件的整个流程都走完了。但是还差一些内容如Subscription类,EventBus中事件类型到事件处理器之间的映射就是通过Map<Class<?>, CopyOnWriteArrayList<Subscription>>
subscriptionsByEventType集合中存储的Subscription对象来获取的。还有用于对订阅对象中使用@Subscribe标注的方法的解析工具——SubscriberMethodFinder没有介绍。以及最后用于指定事件处理方法执行线程的HandlerPoster、BackgroundPoster和AsyncPoster类。下面我们按照上面提到的顺序依次进行介绍!
上面两个对象都很简单!就不废话了。
SubscriberMethodFinder@SubscriberMethodFinder.class
SubscriberMethodFinder对象最主要的就是他的findSubscriberMethods方法!它是整个@Subscribe标注的方法转化为SubscriberMethod对象的方法入口。SubscriberMethodFinder对象中其它的方法都是为这个方法服务的!
findSubscriberMethods()@SubscriberMethodFinder.class
1、从方法缓存池中尝试获取subscriberClass对应的List<SubscriberMethod>集合,如果获取到了则直接返回,不再需要进行解析操作。这个对Android的Activity和Fragment有很好的优化,因为Activity和Fragment经常会进行切换,重复的创建新对象。
2、ignoreGeneratedIndex默认为false,因此执行这一步,调用findUsingInfo方法,接着就进行介绍
3、上面得到的List<SubscriberMethod>集合存入方法缓存池中,返回该集合
findUsingInfo()@SubscriberMethodFinder.class
1、从FindState池——FIND_STATE_POOL中获取一个FindState对象。具体内容参见后面的内容
2、给FindState的域进行如下初始化subscriberClass=clazz=subscriberClass、subscriberInfo=null、skipSuperClasses=false。具体内容参见FindState.class
3、默认情况下该方法用于是为null
4、该方法会将findState.clazz域中使用了@subscribe标注、方法中只有一个参数、且方法修饰符为public的方法,创建一个SubscriberMethod对象,并添加到findState的List<SubscriberMethod>集合中。
5、将findState.clazz域更新为clazz = clazz.getSuperclass(); 如果该超类名字以java. javax.
android.开头则clazz变成null;不再网上寻找父类;
6、拷贝一份findState的List<SubscriberMethod>集合并返回,最后回收findState对象;具体内容参考对应方法源码
prepareFindState()@SubscriberMethodFinder.class
该方法的作用就是首先尝试从FIND_STATE_POOL即FindState池中获取一个FindState对象,如果获取不到则创建一个FindState对象;这样做的好处是提高FindState对象的利用率,避免了重复创建FindState对象。跟okio中的SegmentPool异曲同工之妙。
getSubscriberInfo()@SubscriberMethodFinder.class
默认情况下,即subscriberInfoIndexes和findState.subscriberInfo都为null!则该方法永远是返回null
findUsingReflectionInSingleClass()@SubscriberMethodFinder.class
1、获取订阅类声明的所有方法; 然后对获取到的方法全部遍历一遍
2、获取方法的修饰符:即方法前面的public、private等关键字。
3、走到这里才算是真正获取到了一个正常的事件处理方法,即该类方法使用了@subscribe标注、方法中只有一个参数、且方法修饰符为public。findState.checkAdd(method, eventType)近似findState.anyMethodByEventType.put(eventType,
method); 如果之前没有存在过则返回true
4、判断@Subscribe标注中的threadMode对应的值,默认模式ThreadMode.POSTING
5、创建一个SubscriberMethod对象,该对象很简单就是保存有方法、方法参数类型、线程模式、订阅的优先级、sticky标志位。与Retrofit类似只是这里创建了一个SubscriberMethod对象。并将该对象添加到FindSate的List<SubscriberMethod>集合中。
getMethodsAndRelease()@SubscriberMethodFinder.class
1、拷贝findState对象的List<SubscriberMethod>集合
2、回收findState资源,即把FindState中的各种域该清零的清零,该置空的置空;为下次服务做好准备
3、findState尝试存入FindState池中,而不是直接抛弃
4、返回第一步拷贝得到的List<SubscriberMethod>集合
initForSubscriber()@FindState.class
给FindState的域进行如下初始化subscriberClass=clazz=subscriberClass、subscriberInfo=null、skipSuperClasses=false
checkAdd()@FindState.class
到这里已经完成了Subscription类和SubscriberMethodFinder的学习,现在还剩下几个指定事件处理方法执行线程的HandlerPoster、BackgroundPoster和AsyncPoster类。在HandlerPoster、BackgroundPoster和AsyncPoster类的enqueue方法内部都会先将Subscription
subscription, Object event两个对象包装成一个PengdingPost对象,然后添加进各自的PendingPostQueue队列中,因此我们首先来了解一下PendingPost的内部结构,最后对HandlerPoster、BackgroundPoster和AsyncPoster类进行分析。
PendingPost()@PendingPost.class
obtainPendingPost()@obtainPendingPost.class
releasePendingPost()@obtainPendingPost.class
Fields:
HandlerPoster()@HandlerPoster.class
一般情况,该构造器的第二个参数为Looper.getMainLooper(), 第三个参数为10
enqueue()@HandlerPoster.class
1、创建一个PendingPost对象,该对象保存有一个Subscription subscription, Object event对象但是其构造器是private因此只能通过obtainPendingPost和releasePendingPost方法获取释放一个对象,至于为何使用这样的方式,是因为它内部存储有一个PengdingState对象池,避免了重复的创建删除对象。这种思想在很多地方被用到过。
2、相当于发送一个空消息,用于触发下下面的handleMessage方法
handleMessage()@HandlerPoster.class
1、记录一下任务开始时间;
2、从任务队列中获取一个事件,如果获取不到事件还会重新从中获取一次还是获取不到则返回该方法;
3、回调eventBus的invokeSubscriber方法处理该事件;
4、记录一下本次任务执行的时间,如果超越当前handleMesage所能运行的最长时间则停止循环,发送一个空消息等待系统在合适的时间再来执行HandleMessage方法!
Fields:
BackgroundPoster()@BackgroundPoster.class
enqueuer()@BackgroundPoster.class
1、将PendingPost对象添加到队列中
2、如果当前对象的run方法没有在ExecutorService中执行,对应executorRunning标志位为false;则将当前对象交给EventBus的ExecutorService执行,当前类实现了Runnable方法;Executor对应一个线程池Executors.newCachedThreadPool();
run()@BackgroundPoster.class
跟HandlerPoster的HandlerMessage的逻辑类似,不断的从队列中获取事件进行分发;与HandlerPoster不同之处在于它没有执行时间的限制,可以一直运行直到将队列中的事件全部分发完毕。
Fields:
AsyncPoster()@AsyncPoster.class
enqueue()@AsyncPoster.class
将PendingPost对象添加到队列中,随后将将当前对象交给EventBus的ExecutorService执行,注意这里没有使用executorRunning标志位
run()@AsyncPoster.class
AsyncPoster与BackgroundPoster的最大区别在于:AsyncPoster接收到一个事件先将该事件添加进事件队列中,随后立即将自己添加到ExecutorService线程池中申请一条线程派送事件,该线程只完成从队列中获取一个事件进行处理,随后结束任务。因此可以说AsyncPoster是对接收到的每一个事件都申请一条独立的线程进行分派,而BackgroundPoster是在一条线程中分派接收到的事件。
到此为止我们对于EventBus整个的分析就到此结束了。简单回顾一下,EventBus对象有有两个集合(HashMap)分别以订阅者对象(Object)和事件类型(Class)为键,依次对应一个ArrayList<Classs>事件接收类型集合和一个CopyOnWriteArrayList<Subscription>事件处理集合。每一个事件处理方法(即使用了@Subscribe标注的方法)对应一个SubscribeMethod对象。一个SubscribeMethod对象和一个订阅者对象(Obejct)构成一个Subscription对象。EventBus接收到一个事件先获取该事件对应的所有关联类,每一个关联类又对应一个CopyOnWriteArrayList<Subscription>事件处理集合,用集合中的Subscription对象的subscribeMethod.method.invoke(Subscription.subscribe,event)方法去处理事件。HandlerPoster会将invoke方法在UI线程中执行,BackgroudPoster会线程池中申请一条线程执行invoke方法,AsynPoster保证每个事件都在一条独立的线程中(非UI)执行。
最后补充一点的是为何使用CopyOnWriteArrayList<Subscription>集合存储Subscription对象?而不用普通的ArrayList集合,因为CopyOnWriteArrayList是线程安全集合,内部实现大体上跟ArrayList相似,但是在对该集合进行修改时使用了ReentrantLock锁,保证了同一时间只有一个线程可以修改该集合中的数据。因为EventBus是为多个线程提供事件分发服务,因此必须要考虑到线程安全问题。如果没有特殊需求建议使用EventBus提供的单例模式,即通过EventBus.getDefault()获取一个EventBus实例。
reference:
http://greenrobot.org/eventbus/documentation/
https://github.com/greenrobot/EventBus
https://guides.codepath.com/android/Communicating-with-an-Event-Bus#replacing-local-broadcast-managers-with-eventbus
http://nerds.weddingpartyapp.com/tech/2014/12/24/implementing-an-event-bus-with-rxjava-rxbus/(这里提供了一种新思路使用RxJava实现Event
Bus代替Otto)
转载请注明出处:/article/7733231.html
简单介绍
EventBus是一个用于简化Andorid、Fragment、Threads、Service之间信息传递的一个发布/订阅事件集。传统的Android组件之间的通信方式有:Activity之间使用Intent;Service向Activity发送broadcast;Fragment和Activity之间相互持有对方的引用(随后可以调用对方的相关方法进行事件传递)。传统的事件传递的问题在于:通信方式没有实现解耦,是硬编码在组件中的。组件一旦发生修改,对应的通信方式就需要跟着修改。其实不管什么场景下,我们最好能够使得自己编写的代码最大限度的解耦,这是一个很好的习惯,避免无用功,提高代码利用率。
使用EventBus的建议:
并不建议将应用中所有的事件都通过EventBus进行发送,尤其对于一对一的组件之间通信,建议不要使用EventBus。EventBus的使用场景更像是一种广播,当我们向EventBus发送一个事件,则该事件将会传递给多个该事件的订阅者,比如Service向Activities发送事件。跟LoacalBroadCast有点近似
在Activity和Fragment中使用EventBus时,要注意在组件的生命周期开始时registered EventBus,在生命周期结束时unregistered EventBus。否则容易导致OOM;
使用EventBus的好处在于:
简化组件之间的通信方式
让业务代码更加简洁(但是需要配合相应注解进行使用)
可以指定事件处理方法的执行线程,和订阅者的优先级(跟广播类似)
足够的稳定,已经被很多Android应用使用,你绝对不是第一个吃螃蟹的人
EventBus实现了解耦,事件的创建和分发由EventBus管理,工作在一个单独的线程。EventBus的工作原理如下图:
基本使用
一、引入依赖compile 'org.greenrobot:eventbus:3.0.0' provided 'org.glassfish:javax.annotation:10.0-b28' //解决获取不到@Subscribe注解的问题
二、定义事件
public class IntentServiceResult { int mResult; String mResultValue; IntentServiceResult(int resultCode, String resultValue) { mResult = resultCode; mResultValue = resultValue; } public int getResult() { return mResult; } public String getResultValue() { return mResultValue; } }
三、注册EventBus
public class MainActivity extends AppCompatActivity { @Override protected void onPause() { super.onPause(); EventBus.getDefault().unregister(this); //注:为了后面分析的方便我们对进行注册的对象取名订阅者,如这里的MainActivity.this对象 } @Override protected void onResume() { super.onResume(); EventBus.getDefault().register(this); } }
四、发布事件
EventBus.getDefault().post(new IntentServiceResult(24, "done!!"));
五、创建事件处理方法
public class MainActivity extends AppCompatActivity { @Subscribe(threadMode = ThreadMode.MAIN) public void doThis(IntentServiceResult intentServiceResult) { Toast.makeText(this, intentServiceResult.getResultValue(), Toast.LENGTH_SHORT).show(); } }
此处的threadMode = ThreadMode.MAIN表明下面的事件处理方法在 ThreadMode.MAIN线程中执行,默认会在EventBus的工作线程中执行(发送post事件方法所在的线程)。
ThreadMode.POSTING:在和发送事件相同的线程中执行。默认的线程模式
ThreadMode.MAIN:Android的UI线程中执行。
ThreadMode.BACKGROUND:交给EventBus的一条幕后线程去执行,注意EventBus中只有一个这样的幕后线程,所以的异步方法会在这条线程中顺序执行。要求事件处理方法不要耗时太长!
ThreadMode.ASYNC:在一个单独的线程中执行,总是和发送事件的线程以及UI线程相隔离。将每个这样的事件处理方法扔到一个线程池申请一条线程进行处理。对于网络请求等可以使用这种模式!
源码学习
学习之前问问自己目的是什么,这次学习我们只是想了解以下内容EventBus内部存储有哪些域,我们通过getDefault方法获取到的是不是它的一个单例?
EventBus的unregister和register方法内部是怎样的业务逻辑。是简单的将该对象添加一个集合,然后像Retrofit那样为每个使用了@Susbcribe标注的Method创建一个ServiceMethod?
EventBus的post方法内部的业务逻辑、是去遍历调用注册了该事件的方法来处理该事件?如何快速的找到注册了该事件的方法(Map)?
使用了@Subscribe(threadMode = ThreadMode.MAIN)标注的方法为何会在指定的线程中执行?
EventBus.class
Fields:/*****下面的数据在EventBus自身构造器中被创建*****/ private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; //以事件类型为key,该事件对应的Subscription集合为value;此处使用CopyOnWrite的好处在于它是线程安全的集合,同一时间只有一个线程可以修改该集合的数据! private final Map<Object, List<Class<?>>> typesBySubscriber; //以注册EventBus的对象(该对象会接收EventBus发来的事件)为key,该对象接收的事件类型为Value private final Map<Class<?>, Object> stickyEvents; //sticky在@Subscribe标注时设置(sticky=true), sticky默认是false;直译过来是粘性事件、说人话那就是该类事件会一直被EventBus所保存,除非用户手动删除!同时从Map<Class<?>, Object>可以看出任何类型的事件只会保存一个对应的实例! private final HandlerPoster mainThreadPoster; //对应ThreadMode.MAIN模式,是一个继承Handler的类 private final BackgroundPoster backgroundPoster; //对应ThreadMode.BACKGROUND模式,是一个实现了Runnable方法的类 private final AsyncPoster asyncPoster; //对应ThreadMode.ASYNC模式,是一个实现了Runnable方法的类 /*****下面的数据都是来自EventBusBuilder*****/ private final int indexCount; //一般情况为0,是EventBuilder.subscriberInfoIndexes.size()的值 private final SubscriberMethodFinder subscriberMethodFinder; //订阅方法查找器负责对目标对象中使用了@Subscribe进行标注的方法进行解析得到一个SubscriberMethod对象 private final boolean logSubscriberExceptions; //一般情况为true private final boolean logNoSubscriberMessages; //一般情况为true private final boolean sendSubscriberExceptionEvent; //一般情况为true private final boolean sendNoSubscriberEvent; //一般情况为true private final boolean throwSubscriberException; //一般情况为false private final boolean eventInheritance; //一般情况为true,事件是否具有传递性的标志位 private final ExecutorService executorService; //执行器,对应一个Executors.newCachedThreadPool()线程池 /*****下面的对象创建时初始化或者类加载时初始化*****/ static volatile EventBus defaultInstance; //单例 private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder(); //创建EventBus对象的Builder private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>(); //以事件类型为key,其对应的所以父类、实现的所有接口及接口父类为value private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } }; //当前线程的PostingThreadState对象,之后通过get方法获取该对象
接着我们看看使用getDefault方法得到的EventBus对象
getDefault()@EventBus.class
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) {defaultInstance = new EventBus();} } } return defaultInstance; }
一个很经典的单例模式,调用EventBus的构造器创建EventBus对象;
EventBus()@EventBus.class
public EventBus() { this(DEFAULT_BUILDER); } EventBus(EventBusBuilder builder) { subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; //一般情况为0 subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex); //一般情况参数为null、false、false;该对象我们后面会介绍 logSubscriberExceptions = builder.logSubscriberExceptions; //一般情况为true logNoSubscriberMessages = builder.logNoSubscriberMessages; //一般情况为true sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; //一般情况为true sendNoSubscriberEvent = builder.sendNoSubscriberEvent;//一般情况为true throwSubscriberException = builder.throwSubscriberException; //一般情况为false eventInheritance = builder.eventInheritance; //一般情况为true executorService = builder.executorService; //一个newCachedThreadPool() }
EventBusBuilder.class
Fields:
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(); List<SubscriberInfoIndex> subscriberInfoIndexes; boolean strictMethodVerification; boolean ignoreGeneratedIndex; boolean logSubscriberExceptions = true; boolean logNoSubscriberMessages = true; boolean sendSubscriberExceptionEvent = true; boolean sendNoSubscriberEvent = true; boolean throwSubscriberException; boolean eventInheritance = true; ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; //总结:eventInheritance、logXX和sendXX全为true;其它全为false;
到此为止我们分析了调用getDefault方法得到的EventBus对象;
该对象存储有如下两个集合
Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
以事件类型为键,每个事件对应一个Subscription对象的集合。EventBus一旦收到一个事件就会遍历它对应的Subscription集合,将该事件推送给Subscription处理。对于Subscription对象的如何构建和使用后文将会给出。
Map<Object, List<Class<?>>> typesBySubscriber;
以事件订阅者为键(事件订阅者就是register方法的参数),每个订阅者对应一组它能接收的事件类型集合。一旦订阅者和EventBus解除注册,即调用unregister方法时,EventBus就会取出订阅者对应的所有事件类型,去subscriptionsByEventType中移除该事件对应的Subscription对象集合中的和订阅者关联的Subscription。
该对象存储有如下四个执行器
ExecutorService executorService = Executors.newCachedThreadPool();
是一个线程池,ThreadPoolExecutor(0.Integer.MAX_VALUE,....)
HandlerPoster mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
对应ThreadMode.MAIN模式,是一个继承Handler的类;事件的推送在其HandlerMessage方法中执行
private final BackgroundPoster backgroundPoster;
对应ThreadMode.BACKGROUND模式,是一个实现了Runnable方法的类;事件的推送就是将自己扔给executorService,如果当前对象已经在执行了,则只是将事件放入到BackgroundPoster中的一个队列中;否则将自己交给线程池执行其run方法。BackgroundPoster对象的run方法会一直遍历这个队列,直到队列没有数据则退出run方法。
private final AsyncPoster asyncPoster;
对应ThreadMode.ASYNC模式,是一个实现了Runnable方法的类;相对于BackgroundPoster这里一旦有事件需要分发则立即将自己扔给线程池,而不是直接将事件扔给队列就完了。
本节后面还会对上述这些执行器进行详细的说明。下面我们先来分析下EventBus的register方法。
register()@EventBus.class
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); //note1 synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { //note2 subscribe(subscriber, subscriberMethod); } } }
1、从subscriberMethodFinder中获取subscriberClass (注意这里是Class对象不是Obejct对象) 对应的使用了@Subscribe标注的方法集合;大体流程:从缓存区中尝试获取,获取不到再利用FindSubscriber中的FindState去解析subscriberclass对象。SubscriberMethodFinder.findSubscriberMethods方法参考后面的SubscriberMethodFinder.class部分的介绍。实在憋不住就先跳到那里看看如何实现-->
2、遍历集合List<SubscriberMethod>中的每个元素,调用subscribe方法处理。SubscriberMethod是对使用了@Subscribe标注的方法的解析,该对象包含有方法(Method)、方法参数类型(Type)、线程模式(ThreadMode)、订阅的优先级。SubscriberMethod与Retrofit为每个采用了标注的方法创建ServiceMethod对象的做法类似。
下面我们看看subscribe方法底层实现。
subscribe()@EventBus.class
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType; //note1 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //note2 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); //note3 if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { if (subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } int size = subscriptions.size(); //note4 for (int i = 0; i <= size; i++) { if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } } List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); //note5 if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); if (subscriberMethod.sticky) { //note6 if (eventInheritance) { Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); for (Map.Entry<Class<?>, Object> entry : entries) { Class<?> candidateEventType = entry.getKey(); if (eventType.isAssignableFrom(candidateEventType)) { //从stickyEvents获取对应的事件交给当前事件订阅者处理 Object stickyEvent = entry.getValue(); checkPostStickyEventToSubscription(newSubscription, stickyEvent); //该方法底层还是会执行postToSubscription方法 } } } else { Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } }
1、获取方法参数类型;注意:使用@Subscribe标注的方法有且仅有一个参数
2、利用订阅者对象及其事件处理方法构建一个Subscription对象,该对象存储有Object、SubscriberMethod对象,在本节的最后也贴上了Subscription.class的源码
3、从subscriptionsByEventType集合中获取当前事件对应的Subscription对象集合; 如果得到的集合为空则创建一个这样的集合,并将刚创建的Subscription对象添加进subscriptionsByEventType集合中;如果得到的集合不为空且刚创建的Subscription对象已经存在该集合中则抛出异常,即同一个对象不能注册两次!
4、将第二步创建的Subscription对象按照优先级存入Subscription对象集合中,该集合中的元素都是按照优先级从高到低存放.
5、以subscriber对象为键,从typesBySubscriber获取该对象对应的接收事件类型集合,没有则创建一个这样的集合,然后当前事件类型添加到该集合中,最后将整个集合添加进typesBySubscriber集合中;有则直接添加到接收事件类型集合中;
6、该值默认为false,除非在注册事件方法时使用了如下的标注@Subscribe(sticky = true);那么就会执行到这里。stickyEvent也是EventBus3.0的一大特点,该类事件一旦发送给EventBus,那么EventBus就会将它存入Map<Class<?>,
Object> stickyEvents集合中,key事件类型,value事件实例;每个类型事件对应最新的实例。当订阅对象的某个事件处理方法使用了@Subscribe(sticky = true)标注,EventBus一旦对订阅者完成了注册任务之后,立即将stickyEvents集合中的匹配事件发送给该事件处理进行处理!具体实现就是这里!stickyEvents配套使用的向EventBus发送事件的方法为postSticky,具体内容如下:
public void postSticky(Object event) { synchronized (stickyEvents) { stickyEvents.put(event.getClass(), event); } post(event); }
同时将stickyEvents中某个类型的事件手动删除的方法为:
public <T> T removeStickyEvent(Class<T> eventType) { synchronized (stickyEvents) { return eventType.cast(stickyEvents.remove(eventType)); } }
接着看看unregister方法内部逻辑
unregister()@EventBus.class
public synchronized void unregister(Object subscriber) { List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);//note1 if (subscribedTypes != null) { for (Class<?> eventType : subscribedTypes) { unsubscribeByEventType(subscriber, eventType); // } typesBySubscriber.remove(subscriber); //note3 } else { Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } }
1、从typesBySubscriber获取该对象接收的事件类型集合;
2、对得到的接收事件类型集合中的每个事件类型调用unsubscribeByEventType进行处理;跟着我们就分析该方法
3、该对象从typesBySubscriber集合中移除;
unsubscribeByEventType()@EventBus.class
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); //note1 if (subscriptions != null) { int size = subscriptions.size(); for (int i = 0; i < size; i++) { Subscription subscription = subscriptions.get(i); if (subscription.subscriber == subscriber) { //note2 subscription.active = false; subscriptions.remove(i); i--; size--; } } } }
1、从subscriptionsByEventType集合中获取该事件类型对应的Subscription集合
2、如果集合中的元素——Subscription的subscriber域等于目标subscriber,则将该Subscription从subscriptionsByEventType集合中移除出去;
分析完了register和unregister方法我们接着分析EventBus的最后一个方法——post方法!
post()@EventBus.class
public void post(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); //note1 List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); //note2 if (!postingState.isPosting) { postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState);//note3 } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } }
1、获取当前线程对应的一个PostingThreadState()对象;回顾一下我们在EventBus中创建的如下域
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } //当前推送线程状态 };
ThreadLocal类型的特点是当调用currentPostingThreadState.get()方法的时候,会返回当前线程所持有的一个 PostingThreadState对象;在不同的线程中执行同样一行代码它们得到的对象是不同的。PostingThreadState也很简单,就是定义了一堆数据,没有任何方法。下面就是它的所有源码
final static class PostingThreadState { final List<Object> eventQueue = new ArrayList<Object>(); //待派送的事件队列 boolean isPosting; //当前PostingThreadState对象是否正在派送事件的标志位 boolean isMainThread; //当前PostingThreadState对象是否是工作在UI线程的标志位 Subscription subscription; //事件处理器 Object event; //待处理事件 boolean canceled; //是否取消事件派送的标志位 }
2、向PostingThreadState的事件队列中添加一个事件
3、从PostingThreadState的事件队列——eventQueue中移出一个事件,并调用postSingleEvent方法进行派送
postSingleEvent()@EventBus.class
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; if (eventInheritance) { List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); //note2 int countTypes = eventTypes.size(); for (int h = 0; h < countTypes; h++) { //note3 Class<?> clazz = eventTypes.get(h); subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); } } else { subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); } if (!subscriptionFound) { //note4 if (logNoSubscriberMessages) { Log.d(TAG, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } }
1、eventInheritance该标志位默认为true,表示只要 满足订阅事件是该事件的父类或者实现了该事件同样接口或接口父类 中的任何一个条件的订阅者都会来处理该事件。
2、该方法从名字来看就是获取eventClass的所有父类往上都能追溯到Object、和所有实现的接口、以及接口父类;EventBus进行了优化采用了缓存机制Map<Class<?>, List<Class<?>>> eventTypesCache。
3、将eventClass所有的关联类都通过postSingleEventForEventType进行推送;下面跟着就会分析该方法
4、如果该事件没有推送成功,即没有事件处理器来处理这类事件;系统会尝试发送一个post(new NoSubscriberEvent(this, event))事件
postSingleEventForEventType()@EventBus.class
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { //第一个是带处理的原始事件,第三个参数是原始事件的关联类 CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { subscriptions = subscriptionsByEventType.get(eventClass);//note1 } if (subscriptions != null && !subscriptions.isEmpty()) { for (Subscription subscription : subscriptions) { postingState.event = event; postingState.subscription = subscription; boolean aborted = false; try { postToSubscription(subscription, event, postingState.isMainThread); //note2 aborted = postingState.canceled; } finally { postingState.event = null; postingState.subscription = null; postingState.canceled = false; } if (aborted) { break; } } return true; } return false; }
1、获取原始事件的关联类对应的所有Subscription对象
2、将上述Subscription对象集合进行遍历,使用postToSubscription方法处理原始事件
postToSubscription()@EventBus.class
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { //第一个参数是事件处理器、第二个参数是待处理事件、第三个为当前线程是否是UI线程的标志位 switch (subscription.subscriberMethod.threadMode) { case POSTING: //note1 invokeSubscriber(subscription, event); break; case MAIN: //note2 if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case BACKGROUND: //note3 if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break; case ASYNC: //note4 asyncPoster.enqueue(subscription, event); break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); } }
1、POSTING直接在当前线程执行,调用invokeSubscriber方法
2、MAIN即UI线程执行:如果当前线程就是UI线程则直接调用invokeSubscriber方法,否则将任务交给mainThreadPoster——HandlerPoster(this, Looper.getMainLooper(), 10)对象异步执行,最终会调用invokeSubscriber(PendingPost
pendingPost)方法;后面还会对HandlerPoster类型进行分析,参考HandlerPoster.class源码部分
3、BACKGROUND背景线程执行:其实就在非UI线程中执行,如果当前线程是非UI线程则直接调用invokeSubscriber方法,否则将任务交给backgroundPoster——BackgroundPoster(this)对象异步执行,最终会调用invokeSubscriber(PendingPost pendingPost)方法;后面还会对BackgroundPoster进行分析,参考BackgroundPoster.class源码部分
4、ASYNC:将任务交给 asyncPoster—— AsyncPoster(this)对象异步执行,最终会调用invokeSubscriber(PendingPost pendingPost)方法;后面还会对AsyncPoster进行分析,参考AsyncPoster.class源码部分
invokeSubscriber()@EventBus.class
void invokeSubscriber(Subscription subscription, Object event) { try { subscription.subscriberMethod.method.invoke(subscription.subscriber, event);//note1 } catch (...) { .... } }
1、调用subscriber的对应方法,java反射的知识;
invokeSubscriber()@EventBus.class
void invokeSubscriber(PendingPost pendingPost) { Object event = pendingPost.event; Subscription subscription = pendingPost.subscription; PendingPost.releasePendingPost(pendingPost); if (subscription.active) { invokeSubscriber(subscription, event); //note1 } }
1、该方法与前面的方法类似,只是接受参数不同而已,内部还是会调用 invokeSubscriber(subscription, event)方法!
到此为止我们对于EventBus的注册、注销、发送事件、接收事件的整个流程都走完了。但是还差一些内容如Subscription类,EventBus中事件类型到事件处理器之间的映射就是通过Map<Class<?>, CopyOnWriteArrayList<Subscription>>
subscriptionsByEventType集合中存储的Subscription对象来获取的。还有用于对订阅对象中使用@Subscribe标注的方法的解析工具——SubscriberMethodFinder没有介绍。以及最后用于指定事件处理方法执行线程的HandlerPoster、BackgroundPoster和AsyncPoster类。下面我们按照上面提到的顺序依次进行介绍!
Subscription.class
final class Subscription { final Object subscriber; //订阅者 final SubscriberMethod subscriberMethod; //对订阅者使用@Subscribe标注的方法进行转化后得到的对象 volatile boolean active; Subscription(Object subscriber, SubscriberMethod subscriberMethod) { this.subscriber = subscriber; this.subscriberMethod = subscriberMethod; active = true; } @Override public boolean equals(Object other) { if (other instanceof Subscription) { Subscription otherSubscription = (Subscription) other; return subscriber == otherSubscription.subscriber &&subscriberMethod.equals(otherSubscription.subscriberMethod); } else { return false; } } @Override public int hashCode() { return subscriber.hashCode() + subscriberMethod.methodString.hashCode();}//map集合中会用到 }
SubscriberMethod.class
public class SubscriberMethod { final Method method; final ThreadMode threadMode; //Method线程模式,确定当前Method执行的线程 final Class<?> eventType; //Method接收的参数类型 final int priority; //Method的优先级 final boolean sticky; //@Subscribe sticky标志位 public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) { this.method = method; this.threadMode = threadMode; this.eventType = eventType; this.priority = priority; this.sticky = sticky; } .... }
上面两个对象都很简单!就不废话了。
SubscriberMethodFinder.class
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>(); /*以订阅者为key, 以对订阅者使用@Subscribe标注的方法进行转化后得到的SubscriberMethod对象集合为value;用作缓存,毕竟解析过程会比较耗时。 注意!!!!!这里的MAP的key是订阅者对应的Class对象,而不是订阅者本身(Object对象);因为SubscribeMethod只跟Class有关而跟具体的Object无关; 一个类的不同实例具有同样的SubscribeMethod对象!而EventBus中必须以Object为key,因为事件处理方法大多数不是静态方法, 可能需要访问所属对象的状态(对象中的非static域)!*/ private static final int POOL_SIZE = 4; private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE]; //FindState的对象池,对象池是一种提高资源重复利用率普遍采用的一种做法 private List<SubscriberInfoIndex> subscriberInfoIndexes; //默认为空 private final boolean strictMethodVerification; //默认为false private final boolean ignoreGeneratedIndex; //默认为false
SubscriberMethodFinder@SubscriberMethodFinder.class
SubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification, boolean ignoreGeneratedIndex) { //一般情况参数为null、false、false this.subscriberInfoIndexes = subscriberInfoIndexes; this.strictMethodVerification = strictMethodVerification; this.ignoreGeneratedIndex = ignoreGeneratedIndex; }
SubscriberMethodFinder对象最主要的就是他的findSubscriberMethods方法!它是整个@Subscribe标注的方法转化为SubscriberMethod对象的方法入口。SubscriberMethodFinder对象中其它的方法都是为这个方法服务的!
findSubscriberMethods()@SubscriberMethodFinder.class
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); //note1 if (subscriberMethods != null) { return subscriberMethods; } if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else { subscriberMethods = findUsingInfo(subscriberClass); } //note2 if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation"); } else { METHOD_CACHE.put(subscriberClass, subscriberMethods); //note3 return subscriberMethods; } }
1、从方法缓存池中尝试获取subscriberClass对应的List<SubscriberMethod>集合,如果获取到了则直接返回,不再需要进行解析操作。这个对Android的Activity和Fragment有很好的优化,因为Activity和Fragment经常会进行切换,重复的创建新对象。
2、ignoreGeneratedIndex默认为false,因此执行这一步,调用findUsingInfo方法,接着就进行介绍
3、上面得到的List<SubscriberMethod>集合存入方法缓存池中,返回该集合
findUsingInfo()@SubscriberMethodFinder.class
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState();//note1 findState.initForSubscriber(subscriberClass); //note2 while (findState.clazz != null) { findState.subscriberInfo = getSubscriberInfo(findState); //note3 if (findState.subscriberInfo != null) { SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); } } } else { findUsingReflectionInSingleClass(findState); } //note4 findState.moveToSuperclass(); //note5 } return getMethodsAndRelease(findState); //note6 }
1、从FindState池——FIND_STATE_POOL中获取一个FindState对象。具体内容参见后面的内容
2、给FindState的域进行如下初始化subscriberClass=clazz=subscriberClass、subscriberInfo=null、skipSuperClasses=false。具体内容参见FindState.class
3、默认情况下该方法用于是为null
4、该方法会将findState.clazz域中使用了@subscribe标注、方法中只有一个参数、且方法修饰符为public的方法,创建一个SubscriberMethod对象,并添加到findState的List<SubscriberMethod>集合中。
5、将findState.clazz域更新为clazz = clazz.getSuperclass(); 如果该超类名字以java. javax.
android.开头则clazz变成null;不再网上寻找父类;
6、拷贝一份findState的List<SubscriberMethod>集合并返回,最后回收findState对象;具体内容参考对应方法源码
prepareFindState()@SubscriberMethodFinder.class
private FindState prepareFindState() { synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { FindState state = FIND_STATE_POOL[i]; if (state != null) { FIND_STATE_POOL[i] = null; return state; } } } return new FindState(); }
该方法的作用就是首先尝试从FIND_STATE_POOL即FindState池中获取一个FindState对象,如果获取不到则创建一个FindState对象;这样做的好处是提高FindState对象的利用率,避免了重复创建FindState对象。跟okio中的SegmentPool异曲同工之妙。
getSubscriberInfo()@SubscriberMethodFinder.class
private SubscriberInfo getSubscriberInfo(FindState findState) { if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) { //note1 SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo(); if (findState.clazz == superclassInfo.getSubscriberClass()) { return superclassInfo; } } if (subscriberInfoIndexes != null) { for (SubscriberInfoIndex index : subscriberInfoIndexes) { SubscriberInfo info = index.getSubscriberInfo(findState.clazz); if (info != null) { return info; } } } return null; }
默认情况下,即subscriberInfoIndexes和findState.subscriberInfo都为null!则该方法永远是返回null
findUsingReflectionInSingleClass()@SubscriberMethodFinder.class
private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { methods = findState.clazz.getDeclaredMethods(); //note1 } catch (Throwable th) { methods = findState.clazz.getMethods(); findState.skipSuperClasses = true; //跳过超类标志位设为true } for (Method method : methods) { int modifiers = method.getModifiers(); //note2 if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1) { Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); if (subscribeAnnotation != null) { Class<?> eventType = parameterTypes[0]; if (findState.checkAdd(method, eventType)) { //note3 ThreadMode threadMode = subscribeAnnotation.threadMode(); //note4 findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); //note5 } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException("@Subscribe method " + methodName + "must have exactly 1 parameter but has " + parameterTypes.length); } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } //end of for }
1、获取订阅类声明的所有方法; 然后对获取到的方法全部遍历一遍
2、获取方法的修饰符:即方法前面的public、private等关键字。
3、走到这里才算是真正获取到了一个正常的事件处理方法,即该类方法使用了@subscribe标注、方法中只有一个参数、且方法修饰符为public。findState.checkAdd(method, eventType)近似findState.anyMethodByEventType.put(eventType,
method); 如果之前没有存在过则返回true
4、判断@Subscribe标注中的threadMode对应的值,默认模式ThreadMode.POSTING
5、创建一个SubscriberMethod对象,该对象很简单就是保存有方法、方法参数类型、线程模式、订阅的优先级、sticky标志位。与Retrofit类似只是这里创建了一个SubscriberMethod对象。并将该对象添加到FindSate的List<SubscriberMethod>集合中。
getMethodsAndRelease()@SubscriberMethodFinder.class
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) { List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods); //note1 findState.recycle(); //note2 synchronized (FIND_STATE_POOL) { //note3 for (int i = 0; i < POOL_SIZE; i++) { if (FIND_STATE_POOL[i] == null) { FIND_STATE_POOL[i] = findState; break; } } } return subscriberMethods; //note4 }
1、拷贝findState对象的List<SubscriberMethod>集合
2、回收findState资源,即把FindState中的各种域该清零的清零,该置空的置空;为下次服务做好准备
3、findState尝试存入FindState池中,而不是直接抛弃
4、返回第一步拷贝得到的List<SubscriberMethod>集合
FindState.class@SubscriberMethodFinder.class
Fieldsfinal Map<Class, Object> anyMethodByEventType = new HashMap<>(); final List<SubscriberMethod> subscriberMethods = new ArrayList<>(); Class<?> subscriberClass; Class<?> clazz; //用以遍历subscriberClass的所有父类 boolean skipSuperClasses; SubscriberInfo subscriberInfo;
initForSubscriber()@FindState.class
void initForSubscriber(Class<?> subscriberClass) { this.subscriberClass = clazz = subscriberClass; skipSuperClasses = false; //不跳过当前类的父类 subscriberInfo = null; }
给FindState的域进行如下初始化subscriberClass=clazz=subscriberClass、subscriberInfo=null、skipSuperClasses=false
checkAdd()@FindState.class
boolean checkAdd(Method method, Class<?> eventType) { Object existing = anyMethodByEventType.put(eventType, method); if (existing == null) { return true; } ...... }
到这里已经完成了Subscription类和SubscriberMethodFinder的学习,现在还剩下几个指定事件处理方法执行线程的HandlerPoster、BackgroundPoster和AsyncPoster类。在HandlerPoster、BackgroundPoster和AsyncPoster类的enqueue方法内部都会先将Subscription
subscription, Object event两个对象包装成一个PengdingPost对象,然后添加进各自的PendingPostQueue队列中,因此我们首先来了解一下PendingPost的内部结构,最后对HandlerPoster、BackgroundPoster和AsyncPoster类进行分析。
PendingPost.class
Fields:private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>(); //PendingPost对象池 Object event; //待处理事件 Subscription subscription; //处理上述事件的方法 PendingPost next;
PendingPost()@PendingPost.class
private PendingPost(Object event, Subscription subscription) { this.event = event; this.subscription = subscription; }
obtainPendingPost()@obtainPendingPost.class
static PendingPost obtainPendingPost(Subscription subscription, Object event) { synchronized (pendingPostPool) { int size = pendingPostPool.size(); if (size > 0) { PendingPost pendingPost = pendingPostPool.remove(size - 1); pendingPost.event = event; pendingPost.subscription = subscription; pendingPost.next = null; return pendingPost; } } return new PendingPost(event, subscription); }
releasePendingPost()@obtainPendingPost.class
static void releasePendingPost(PendingPost pendingPost) { pendingPost.event = null; pendingPost.subscription = null; pendingPost.next = null; synchronized (pendingPostPool) { if (pendingPostPool.size() < 10000) {pendingPostPool.add(pendingPost); } } } }
HandlerPoster.class
final class HandlerPoster extends HandlerFields:
private final PendingPostQueue queue; private final EventBus eventBus; private boolean handlerActive; private final int maxMillisInsideHandleMessage;
HandlerPoster()@HandlerPoster.class
HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { super(looper); this.eventBus = eventBus; this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; queue = new PendingPostQueue(); }
一般情况,该构造器的第二个参数为Looper.getMainLooper(), 第三个参数为10
enqueue()@HandlerPoster.class
void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); //note1 synchronized (this) { queue.enqueue(pendingPost); if (!handlerActive) { handlerActive = true; if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message");}//note2 } } }
1、创建一个PendingPost对象,该对象保存有一个Subscription subscription, Object event对象但是其构造器是private因此只能通过obtainPendingPost和releasePendingPost方法获取释放一个对象,至于为何使用这样的方式,是因为它内部存储有一个PengdingState对象池,避免了重复的创建删除对象。这种思想在很多地方被用到过。
2、相当于发送一个空消息,用于触发下下面的handleMessage方法
handleMessage()@HandlerPoster.class
public void handleMessage(Message msg) { boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); //note1 while (true) { PendingPost pendingPost = queue.poll(); //note2 if (pendingPost == null) { synchronized (this) { pendingPost = queue.poll(); if (pendingPost == null) { handlerActive = false; return;} } } eventBus.invokeSubscriber(pendingPost); //note3 long timeInMethod = SystemClock.uptimeMillis() - started; //note4 if (timeInMethod >= maxMillisInsideHandleMessage) { if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); } rescheduled = true; return; } } } finally { handlerActive = rescheduled; } } }
1、记录一下任务开始时间;
2、从任务队列中获取一个事件,如果获取不到事件还会重新从中获取一次还是获取不到则返回该方法;
3、回调eventBus的invokeSubscriber方法处理该事件;
4、记录一下本次任务执行的时间,如果超越当前handleMesage所能运行的最长时间则停止循环,发送一个空消息等待系统在合适的时间再来执行HandleMessage方法!
BackgroundPoster.class
final class BackgroundPoster implements RunnableFields:
private final PendingPostQueue queue; private final EventBus eventBus; private volatile boolean executorRunning;
BackgroundPoster()@BackgroundPoster.class
BackgroundPoster(EventBus eventBus) { this.eventBus = eventBus; queue = new PendingPostQueue(); }
enqueuer()@BackgroundPoster.class
public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized (this) { queue.enqueue(pendingPost); //note1 if (!executorRunning) { executorRunning = true; eventBus.getExecutorService().execute(this); //note2 } } }
1、将PendingPost对象添加到队列中
2、如果当前对象的run方法没有在ExecutorService中执行,对应executorRunning标志位为false;则将当前对象交给EventBus的ExecutorService执行,当前类实现了Runnable方法;Executor对应一个线程池Executors.newCachedThreadPool();
run()@BackgroundPoster.class
public void run() { try { try { while (true) { PendingPost pendingPost = queue.poll(1000); if (pendingPost == null) { synchronized (this) { pendingPost = queue.poll(); if (pendingPost == null) {executorRunning = false; return;} } } eventBus.invokeSubscriber(pendingPost); //思路都是一样的 }//end of while }//end of second try catch (InterruptedException e) { Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);} } //end of first try finally { executorRunning = false; } }//end of function
跟HandlerPoster的HandlerMessage的逻辑类似,不断的从队列中获取事件进行分发;与HandlerPoster不同之处在于它没有执行时间的限制,可以一直运行直到将队列中的事件全部分发完毕。
AsyncPoster.class
class AsyncPoster implements Runnable {Fields:
private final PendingPostQueue queue; private final EventBus eventBus;
AsyncPoster()@AsyncPoster.class
AsyncPoster(EventBus eventBus) { this.eventBus = eventBus; queue = new PendingPostQueue(); }
enqueue()@AsyncPoster.class
public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); queue.enqueue(pendingPost); eventBus.getExecutorService().execute(this); }
将PendingPost对象添加到队列中,随后将将当前对象交给EventBus的ExecutorService执行,注意这里没有使用executorRunning标志位
run()@AsyncPoster.class
public void run() { PendingPost pendingPost = queue.poll(); if(pendingPost == null) {throw new IllegalStateException("No pending post available"); } eventBus.invokeSubscriber(pendingPost); } }
AsyncPoster与BackgroundPoster的最大区别在于:AsyncPoster接收到一个事件先将该事件添加进事件队列中,随后立即将自己添加到ExecutorService线程池中申请一条线程派送事件,该线程只完成从队列中获取一个事件进行处理,随后结束任务。因此可以说AsyncPoster是对接收到的每一个事件都申请一条独立的线程进行分派,而BackgroundPoster是在一条线程中分派接收到的事件。
到此为止我们对于EventBus整个的分析就到此结束了。简单回顾一下,EventBus对象有有两个集合(HashMap)分别以订阅者对象(Object)和事件类型(Class)为键,依次对应一个ArrayList<Classs>事件接收类型集合和一个CopyOnWriteArrayList<Subscription>事件处理集合。每一个事件处理方法(即使用了@Subscribe标注的方法)对应一个SubscribeMethod对象。一个SubscribeMethod对象和一个订阅者对象(Obejct)构成一个Subscription对象。EventBus接收到一个事件先获取该事件对应的所有关联类,每一个关联类又对应一个CopyOnWriteArrayList<Subscription>事件处理集合,用集合中的Subscription对象的subscribeMethod.method.invoke(Subscription.subscribe,event)方法去处理事件。HandlerPoster会将invoke方法在UI线程中执行,BackgroudPoster会线程池中申请一条线程执行invoke方法,AsynPoster保证每个事件都在一条独立的线程中(非UI)执行。
最后补充一点的是为何使用CopyOnWriteArrayList<Subscription>集合存储Subscription对象?而不用普通的ArrayList集合,因为CopyOnWriteArrayList是线程安全集合,内部实现大体上跟ArrayList相似,但是在对该集合进行修改时使用了ReentrantLock锁,保证了同一时间只有一个线程可以修改该集合中的数据。因为EventBus是为多个线程提供事件分发服务,因此必须要考虑到线程安全问题。如果没有特殊需求建议使用EventBus提供的单例模式,即通过EventBus.getDefault()获取一个EventBus实例。
reference:
http://greenrobot.org/eventbus/documentation/
https://github.com/greenrobot/EventBus
https://guides.codepath.com/android/Communicating-with-an-Event-Bus#replacing-local-broadcast-managers-with-eventbus
http://nerds.weddingpartyapp.com/tech/2014/12/24/implementing-an-event-bus-with-rxjava-rxbus/(这里提供了一种新思路使用RxJava实现Event
Bus代替Otto)
相关文章推荐
- 使用python将KDD-99中的文本替换为数值形式
- Linux whatis man man: nothing appropriate
- ImageView你不知道的一些问题
- 非阻塞式线程安全列表-ConcurrentLinkedDeque
- js排序1--sort
- Scrum 1.0
- 多线程-wait(针对OBJECT对象锁的方式)
- swift之给拓展Category增加属性
- 类型的判定
- 《java入门第一季》之面向对象(重头戏多态)
- ListView的setOnClickListener失效
- 《java入门第一季》之面向对象(重头戏多态)
- 数位dp
- 防范 DDoS 攻击的 15 个方法
- hi3531 添加uart3
- 怎样判读安装java jvm是32位还是64位的
- sql server 2008 r2安装详解
- Excel自动更新时间
- 封装对象时候时间处理方式
- iOS ---- KVO的内部实现原理