您的位置:首页 > 其它

Eventbus的使用与深入-- 一个好用的开源的事件订阅与发布总线,解放你的handler

2016-07-14 00:06 471 查看

Eventbus已经发布了很长时间,经历了市场和技术的的考验,与otto齐名,下面来简单了解一下eventbus的使用方法与深入探究.

简单介绍

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管理,工作在一个单独的线程。使用方法及其简单:一、引入依赖[java]view plain copycompile 'org.greenrobot:eventbus:3.0.0'provided 'org.glassfish:javax.annotation:10.0-b28' //解决获取不到@Subscribe注解的问题二、定义事件[java]view plain copypublic 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[java]view plain copypublic 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);}}四、发布事件[java]view plain copyEventBus.getDefault().post(new IntentServiceResult(24, "done!!"));五、创建事件处理方法[java]view plain copypublic 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:[java]view plain copy/*****下面的数据在EventBus自身构造器中被创建*****/private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;//以事件类型为key,该事件对应的Subscription集合为value;此处使用CopyOnWrite的好处在于它是线程安全的集合,同一时间只有一个线程可以修改该集合的数据!private final Map<Object, List<Class<?>>> typesBySubscriber;//以注册EventBus的对象(该对象会接收EventBus发来的事件)为key,该对象接收的事件类型为Valueprivate 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;//一般情况为trueprivate final boolean logNoSubscriberMessages;//一般情况为trueprivate final boolean sendSubscriberExceptionEvent;//一般情况为trueprivate final boolean sendNoSubscriberEvent;//一般情况为trueprivate final boolean throwSubscriberException;//一般情况为falseprivate final boolean eventInheritance;//一般情况为true,事件是否具有传递性的标志位private final ExecutorService executorService;//执行器,对应一个Executors.newCachedThreadPool()线程池/*****下面的对象创建时初始化或者类加载时初始化*****/static volatile EventBus defaultInstance;//单例private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();//创建EventBus对象的Builderprivate static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();//以事件类型为key,其对应的所以父类、实现的所有接口及接口父类为valueprivate final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {@Override protected PostingThreadState initialValue() { return new PostingThreadState(); }};//当前线程的PostingThreadState对象,之后通过get方法获取该对象接着我们看看使用getDefault方法得到的EventBus对象getDefault()@EventBus.class[java]view plain copypublic static EventBus getDefault() {if (defaultInstance == null) {synchronized (EventBus.class) {if (defaultInstance == null) {defaultInstance = new EventBus();}}}return defaultInstance;}一个很经典的单例模式,调用EventBus的构造器创建EventBus对象;EventBus()@EventBus.class[java]view plain copypublic 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; //一般情况为0subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex);//一般情况参数为null、false、false;该对象我们后面会介绍logSubscriberExceptions = builder.logSubscriberExceptions; //一般情况为truelogNoSubscriberMessages = builder.logNoSubscriberMessages; //一般情况为truesendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; //一般情况为truesendNoSubscriberEvent = builder.sendNoSubscriberEvent;//一般情况为truethrowSubscriberException = builder.throwSubscriberException; //一般情况为falseeventInheritance = builder.eventInheritance; //一般情况为trueexecutorService = builder.executorService; //一个newCachedThreadPool()}EventBusBuilder.classFields:[java]view plain copyprivate 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[java]view plain copypublic void register(Object subscriber) {Class<?> subscriberClass = subscriber.getClass();List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); //note1synchronized (this) {for (SubscriberMethod subscriberMethod : subscriberMethods) { //note2subscribe(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[java]view plain copyprivate void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {Class<?> eventType = subscriberMethod.eventType; //note1Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //note2CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); //note3if (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(); //note4for (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); //note5if (subscribedEvents == null) {subscribedEvents = new ArrayList<>();typesBySubscriber.put(subscriber, subscribedEvents);}subscribedEvents.add(eventType);if (subscriberMethod.sticky) { //note6if (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,具体内容如下:[java]view plain copypublic void postSticky(Object event) {synchronized (stickyEvents) { stickyEvents.put(event.getClass(), event); }post(event);}同时将stickyEvents中某个类型的事件手动删除的方法为:[java]view plain copypublic <T> T removeStickyEvent(Class<T> eventType) {synchronized (stickyEvents) {return eventType.cast(stickyEvents.remove(eventType));}}接着看看unregister方法内部逻辑unregister()@EventBus.class[java]view plain copypublic synchronized void unregister(Object subscriber) {List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);//note1if (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[java]view plain copyprivate void unsubscribeByEventType(Object subscriber, Class<?> eventType) {List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); //note1if (subscriptions != null) {int size = subscriptions.size();for (int i = 0; i < size; i++) {Subscription subscription = subscriptions.get(i);if (subscription.subscriber == subscriber) { //note2subscription.active = false;subscriptions.remove(i);i--;size--;}}}}1、从subscriptionsByEventType集合中获取该事件类型对应的Subscription集合2、如果集合中的元素——Subscription的subscriber域等于目标subscriber,则将该Subscription从subscriptionsByEventType集合中移除出去;分析完了register和unregister方法我们接着分析EventBus的最后一个方法——post方法!post()@EventBus.class[java]view plain copypublic void post(Object event) {PostingThreadState postingState = currentPostingThreadState.get(); //note1List<Object> eventQueue = postingState.eventQueue;eventQueue.add(event); //note2if (!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中创建的如下域[java]view plain copyprivate final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {@Override protected PostingThreadState initialValue() { return new PostingThreadState(); } //当前推送线程状态};ThreadLocal类型的特点是当调用currentPostingThreadState.get()方法的时候,会返回当前线程所持有的一个 PostingThreadState对象;在不同的线程中执行同样一行代码它们得到的对象是不同的。PostingThreadState也很简单,就是定义了一堆数据,没有任何方法。下面就是它的所有源码[java]view plain copyfinal 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[java]view plain copyprivate void postSingleEvent(Object event, PostingThreadState postingState) throws Error {Class<?> eventClass = event.getClass();boolean subscriptionFound = false;if (eventInheritance) {List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); //note2int countTypes = eventTypes.size();for (int h = 0; h < countTypes; h++) { //note3Class<?> clazz = eventTypes.get(h);subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);}} else {subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);}if (!subscriptionFound) { //note4if (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[java]view plain copyprivate 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); //note2aborted = 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[java]view plain copyprivate void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {//第一个参数是事件处理器、第二个参数是待处理事件、第三个为当前线程是否是UI线程的标志位switch (subscription.subscriberMethod.threadMode) {case POSTING: //note1invokeSubscriber(subscription, event);break;case MAIN: //note2if (isMainThread) {invokeSubscriber(subscription, event);} else {mainThreadPoster.enqueue(subscription, event);}break;case BACKGROUND: //note3if (isMainThread) {backgroundPoster.enqueue(subscription, event);} else {invokeSubscriber(subscription, event);}break;case ASYNC: //note4asyncPoster.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(PendingPostpendingPost)方法;后面还会对BackgroundPoster进行分析,参考BackgroundPoster.class源码部分4、ASYNC:将任务交给 asyncPoster—— AsyncPoster(this)对象异步执行,最终会调用invokeSubscriber(PendingPost pendingPost)方法;后面还会对AsyncPoster进行分析,参考AsyncPoster.class源码部分invokeSubscriber()@EventBus.class[java]view plain copyvoid invokeSubscriber(Subscription subscription, Object event) {try {subscription.subscriberMethod.method.invoke(subscription.subscriber, event);//note1} catch (...) { .... }}1、调用subscriber的对应方法,java反射的知识;invokeSubscriber()@EventBus.class[java]view plain copyvoid 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

[java]view plain copyfinal 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;}@Overridepublic boolean equals(Object other) {if (other instanceof Subscription) {Subscription otherSubscription = (Subscription) other;return subscriber == otherSubscription.subscriber &&subscriberMethod.equals(otherSubscription.subscriberMethod);} else { return false; }}@Overridepublic int hashCode() { return subscriber.hashCode() + subscriberMethod.methodString.hashCode();}//map集合中会用到}

SubscriberMethod.class

[java]view plain copypublic 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

[java]view plain copyprivate 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; //默认为falseprivate final boolean ignoreGeneratedIndex; //默认为falseSubscriberMethodFinder@SubscriberMethodFinder.class[java]view plain copySubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification, boolean ignoreGeneratedIndex) {//一般情况参数为null、false、falsethis.subscriberInfoIndexes = subscriberInfoIndexes;this.strictMethodVerification = strictMethodVerification;this.ignoreGeneratedIndex = ignoreGeneratedIndex;}SubscriberMethodFinder对象最主要的就是他的findSubscriberMethods方法!它是整个@Subscribe标注的方法转化为SubscriberMethod对象的方法入口。SubscriberMethodFinder对象中其它的方法都是为这个方法服务的!findSubscriberMethods()@SubscriberMethodFinder.class[java]view plain copyList<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); //note1if (subscriberMethods != null) { return subscriberMethods; }if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); }else { subscriberMethods = findUsingInfo(subscriberClass); } //note2if (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); //note3return subscriberMethods;}}1、从方法缓存池中尝试获取subscriberClass对应的List<SubscriberMethod>集合,如果获取到了则直接返回,不再需要进行解析操作。这个对Android的Activity和Fragment有很好的优化,因为Activity和Fragment经常会进行切换,重复的创建新对象。2、ignoreGeneratedIndex默认为false,因此执行这一步,调用findUsingInfo方法,接着就进行介绍3、上面得到的List<SubscriberMethod>集合存入方法缓存池中,返回该集合findUsingInfo()@SubscriberMethodFinder.class[java]view plain copyprivate List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {FindState findState = prepareFindState();//note1findState.initForSubscriber(subscriberClass); //note2while (findState.clazz != null) {findState.subscriberInfo = getSubscriberInfo(findState); //note3if (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); } //note4findState.moveToSuperclass(); //note5}return getMethodsAndRelease(findState); //note6}1、从FindState池——FIND_STATE_POOL中获取一个FindState对象。具体内容参见后面的内容2、给FindState的域进行如下初始化subscriberClass=clazz=subscriberClass、subscriberInfo=null、skipSuperClasses=false。具体内容参见FindState.class3、默认情况下该方法用于是为null4、该方法会将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[java]view plain copyprivate 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[java]view plain copyprivate SubscriberInfo getSubscriberInfo(FindState findState) {if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) { //note1SubscriberInfo 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!则该方法永远是返回nullfindUsingReflectionInSingleClass()@SubscriberMethodFinder.class[java]view plain copyprivate 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(); //note2if ((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)) { //note3ThreadMode threadMode = subscribeAnnotation.threadMode(); //note4findState.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); 如果之前没有存在过则返回true4、判断@Subscribe标注中的threadMode对应的值,默认模式ThreadMode.POSTING5、创建一个SubscriberMethod对象,该对象很简单就是保存有方法、方法参数类型、线程模式、订阅的优先级、sticky标志位。与Retrofit类似只是这里创建了一个SubscriberMethod对象。并将该对象添加到FindSate的List<SubscriberMethod>集合中。getMethodsAndRelease()@SubscriberMethodFinder.class[java]view plain copyprivate List<SubscriberMethod> getMethodsAndRelease(FindState findState) {List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods); //note1findState.recycle(); //note2synchronized (FIND_STATE_POOL) { //note3for (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

Fields[java]view plain copyfinal Map<Class, Object> anyMethodByEventType = new HashMap<>();final List<SubscriberMethod> subscriberMethods = new ArrayList<>();Class<?> subscriberClass;Class<?> clazz; //用以遍历subscriberClass的所有父类boolean skipSuperClasses;SubscriberInfo subscriberInfo;initForSubscriber()@FindState.class[java]view plain copyvoid initForSubscriber(Class<?> subscriberClass) {this.subscriberClass = clazz = subscriberClass;skipSuperClasses = false; //不跳过当前类的父类subscriberInfo = null;}给FindState的域进行如下初始化subscriberClass=clazz=subscriberClass、subscriberInfo=null、skipSuperClasses=falsecheckAdd()@FindState.class[java]view plain copyboolean 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方法内部都会先将Subscriptionsubscription, Object event两个对象包装成一个PengdingPost对象,然后添加进各自的PendingPostQueue队列中,因此我们首先来了解一下PendingPost的内部结构,最后对HandlerPoster、BackgroundPoster和AsyncPoster类进行分析。

PendingPost.class

Fields:[java]view plain copyprivate final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>(); //PendingPost对象池Object event; //待处理事件Subscription subscription; //处理上述事件的方法PendingPost next;PendingPost()@PendingPost.class[java]view plain copyprivate PendingPost(Object event, Subscription subscription) {this.event = event;this.subscription = subscription;}obtainPendingPost()@obtainPendingPost.class[java]view plain copystatic 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[java]view plain copystatic 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:[java]view plain copyprivate final PendingPostQueue queue;private final EventBus eventBus;private boolean handlerActive;private final int maxMillisInsideHandleMessage;HandlerPoster()@HandlerPoster.class[java]view plain copyHandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {super(looper);this.eventBus = eventBus;this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;queue = new PendingPostQueue();}一般情况,该构造器的第二个参数为Looper.getMainLooper(),第三个参数为10enqueue()@HandlerPoster.class[java]view plain copyvoid enqueue(Subscription subscription, Object event) {PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); //note1synchronized (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[java]view plain copypublic void handleMessage(Message msg) {boolean rescheduled = false;try {long started = SystemClock.uptimeMillis(); //note1while (true) {PendingPost pendingPost = queue.poll(); //note2if (pendingPost == null) {synchronized (this) {pendingPost = queue.poll();if (pendingPost == null) { handlerActive = false; return;}}}eventBus.invokeSubscriber(pendingPost); //note3long timeInMethod = SystemClock.uptimeMillis() - started; //note4if (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:[java]view plain copyprivate final PendingPostQueue queue;private final EventBus eventBus;private volatile boolean executorRunning;BackgroundPoster()@BackgroundPoster.class[java]view plain copyBackgroundPoster(EventBus eventBus) {this.eventBus = eventBus;queue = new PendingPostQueue();}enqueuer()@BackgroundPoster.class[java]view plain copypublic void enqueue(Subscription subscription, Object event) {PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);synchronized (this) {queue.enqueue(pendingPost); //note1if (!executorRunning) {executorRunning = true;eventBus.getExecutorService().execute(this); //note2}}}1、将PendingPost对象添加到队列中2、如果当前对象的run方法没有在ExecutorService中执行,对应executorRunning标志位为false;则将当前对象交给EventBus的ExecutorService执行,当前类实现了Runnable方法;Executor对应一个线程池Executors.newCachedThreadPool();run()@BackgroundPoster.class[java]view plain copypublic 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 trycatch (InterruptedException e) { Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);}} //end of first tryfinally { executorRunning = false; }}//end of function跟HandlerPoster的HandlerMessage的逻辑类似,不断的从队列中获取事件进行分发;与HandlerPoster不同之处在于它没有执行时间的限制,可以一直运行直到将队列中的事件全部分发完毕。

AsyncPoster.class

class AsyncPoster implements Runnable {Fields:[java]view plain copyprivate final PendingPostQueue queue;private final EventBus eventBus;AsyncPoster()@AsyncPoster.class[java]view plain copyAsyncPoster(EventBus eventBus) {this.eventBus = eventBus;queue = new PendingPostQueue();}enqueue()@AsyncPoster.class[java]view plain copypublic 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[java]view plain copypublic 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实例。用法总结:
private voidinitData() {//1.EventBus注册EventBus.getDefault().register(this);....................}@Overrideprotected voidonDestroy() { //2.EventBus取消注册EventBus.getDefault().unregister(this);//把所有的消息和回调移除.................super.onDestroy();}//3.写方法接收消息==j接收消息以参数为区分,同类型参数才会接收public voidonEventMainThread(MediaItem mediaItem) {//在主线程setViewData();showPlayMode(false);seekbarAudio.setMax((int) mediaItem.getDuration());//发消息更新音频播放的进度handler.sendEmptyMessage(PROGRESS);}//4.发消息EventBus.getDefault().post(mediaItem);//mediaItem为任意类
ThreadMode定义的4个线程类型如下:PostThread:事件响应函数和事件发布在同一线程中执行。这个是默认值,这样可以避免线程切换。MainThread:事件响应函数会在Android应用的主线程(大部分情况下都是UI线程)中执行。BackgroundThread:事件响应函数会在一个后台线程中执行。如果事件发布函数不是在主线程中,则会立即在事件发布线程中执行响应函数。如果事件发布函数在主线程中,EventBus则会在唯一的一个后台线程中按照顺序来执行所有的后台事件响应函数。async:事件响应函数在另外一个异步线程中执行。该线程和发布线程、主线程相互独立。如果事件响应函数需要较长的时间来执行,则应该使用该模式,例如 网络访问等。需要注意的是,由于系统并行的限制,应该避免在同一时间触发大量的异步线程。EventBus使用一个线程池来提高线程的效率。onEventMainThread代表这个方法会在UI线程执行onEventPostThread代表这个方法会在当前发布事件的线程执行BackgroundThread这个方法,如果在非UI线程发布的事件,则直接执行,和发布在同一个线程中。如果在UI线程发布的事件,则加入后台任务队列,使用线程池一个接一个调用。Async 加入后台任务队列,使用线程池调用,注意没有Backgroun

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: