EventBus原理以及源代码分析
一、概述
EventBus是一个基于观察者模式的发布/订阅事件总线框架。将事件的发送者和接收者分开,其可以简化组件之间的通讯,相对于BroadcastReceiver其更轻量级也更易用。
二、用法介绍
EventBus的用法非常的简单,大致上就四步:
1.注册事件
1 2 3 4 5 6 7 8 9 | @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** * 注册观察者对象 */ EventBus.getDefault().register( this ); } |
2.消费事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /** * 用于接收post发送过来的事件 * @param event 具体的事件主体 */ @Subscribe public void onMessageEvent(MessageEvent event) { switch (event.getArg1()) { case 0 : break ; case 1 : break ; } } |
3.取消事件
1 2 3 4 5 6 7 8 | @Override protected void onDestroy() { super .onDestroy(); /** * 取消订阅 */ EventBus.getDefault().unregister( this ); } |
4.发送事件
1 2 3 4 5 6 7 8 9 10 | /** * 发送消息 */ public void toPost() { MessageEvent event = new MessageEvent(); event.setArg1( 0 ); event.setObj( new Object()); event.setMsg( "我发送消息了" ); EventBus.getDefault().post(event); } |
三、具体的源代码分析
1.我们从使用开始入手,先看下EventBus.getDefault()都干了写什么事情。
1 2 3 4 5 6 7 8 9 10 11 12 | public static EventBus getDefault() { EventBus instance = defaultInstance; if (instance == null ) { synchronized (EventBus. class ) { instance = EventBus.defaultInstance; if (instance == null ) { instance = EventBus.defaultInstance = new EventBus(); } } } return instance; } |
从上面的代码我们可以看出EventBus是一个单例类而且是懒汉式的单例,为了保证整个应用中只有一个EventBus实例。
在其构造方法中会进行一些初始化的工作,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public EventBus() { this (DEFAULT_BUILDER); } EventBus(EventBusBuilder builder) { logger = builder.getLogger(); //通过订阅事件类型查找订阅对象的map集合 subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); //粘性事件 stickyEvents = new ConcurrentHashMap<>(); //主线程支持 mainThreadSupport = builder.getMainThreadSupport(); //handler对象 mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster( this ) : null ; //runable对象 backgroundPoster = new BackgroundPoster( this ); //线程池 asyncPoster = new AsyncPoster( this ); indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0 ; //订阅者方法集合 subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; sendNoSubscriberEvent = builder.sendNoSubscriberEvent; throwSubscriberException = builder.throwSubscriberException; eventInheritance = builder.eventInheritance; //默认线程,CachedThreadPool executorService = builder.executorService; } |
1.subscriptionsByEventType通过event.getClass类型查找HashMap中的subscription集合。而subscription中存放的是subscriberMethod对象,subscriberMethod对象中又存放的是订阅者中用subscriber注解标注的Method、时间类型event.getClass、是否是粘性事件、线程模型、时间执行的优先级等信息。
2.mainThreadPoster,其实它是HandlerPoster继承了handler并实现了poster,可以把其理解成主线程handler。调用其enqueue方法传入subscription和subscriber。并在其handleMessage方法中通过eventbus.invokeSubscriber(pendingPost) 放订阅方法在主线程中执行
3.BackgroundPoster实现了runnable和poster对象,通过enqueue方法把subscription和subscriber传入,在run方法中执行eventbus.invokeSubscriber(pendingPost)
4.AsyncPoster实现了Runnable和Poster接口,也是调用enqueue将Subscription和subscriber传入,并将AsyncPoster对象运行在线程池中,并执行run方法的中的eventBus.invokeSubscriber(pendingPost)
5.executorService线程池,其具体实现是CachedThreadPool
以上的几步在后面的分析中会回使用到。
2.EventBus.getDefault().register(this)方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /** * 注册订阅者对象 * @param subscriber 订阅者 */ public void register(Object subscriber) { //获取订阅者的class对象 Class<?> subscriberClass = subscriber.getClass(); //根据订阅者class对象或者订阅者subscribe标注的方法集合SubscriberMethod List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized ( this ) { //加锁,一次只能进一个线程 for (SubscriberMethod subscriberMethod : subscriberMethods) { //开始订阅,循环向subscriptionsByEventType中添加订阅对象。具体的做法是,根据事件类型取出订阅集合,然后向订阅集合中不断的加入 //订阅,并最终存入subscriptionsByEventType中 subscribe(subscriber, subscriberMethod); } } } |
在register方法内部,会获取到订阅者subscriber(activity)的class对象。并通过这个class对象获取到该订阅者中用subscriber标记的方法集合。通过SubscriberMethodFinder.findSubscriberMethods(subscriberClass)获取。
在findSubscriberMethods内部首先会从缓存中获取,如果缓存中又就直接返回,如果缓存中没有就解析subscriberClass对象,并拿到subscriberClass对象中用subscriber注解标注过的方法、方法参数类型、线程模型、事件执行优先级、是否是粘性事件,并将以上信息封装到SubscriberMethod对象中。然后把SubscriberMethod对象加入集合返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { //先从缓存中获取,如果获取到了就直接返回。如果缓存中没有就查找带有subscribe标记的方法,并放到集合中 //因为一个class对象中用subscribe标注的方法可能不止一个,所以要用集合把所有的都存入进去 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null ) { return subscriberMethods; } //是否强制使用反射(即使有生成的索引) if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else { subscriberMethods = findUsingInfo(subscriberClass); } 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); return subscriberMethods; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null ) { //如果订阅者对象不为空,执行下面这个while findUsingReflectionInSingleClass(findState); //去找父类 findState.moveToSuperclass(); } return getMethodsAndRelease(findState); } private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { //利用反射获取subscriber的方法集合 methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { methods = findState.clazz.getMethods(); findState.skipSuperClasses = true ; } for (Method method : methods) { int modifiers = method.getModifiers(); //过滤public标注的方法 if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0 ) { Class<?>[] parameterTypes = method.getParameterTypes(); //获取参数类型 //找出只有一个参数的方法 if (parameterTypes.length == 1 ) { //找出有subscribe注解的方法 Subscribe subscribeAnnotation = method.getAnnotation(Subscribe. class ); if (subscribeAnnotation != null ) { //获取事件类型,由于只有一个参数所以parameterTypes取第一个就行了 Class<?> eventType = parameterTypes[ 0 ]; if (findState.checkAdd(method, eventType)) { //获取线程模型,这个模型用于标注,用户自定义的事件是在主线程中执行还是在子线程中执行 ThreadMode threadMode = subscribeAnnotation.threadMode(); //把订阅者的方法存入subscriberMethod,并把SubscriberMethod存入方法集合中 findState.subscriberMethods.add( new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } ....省略了一些代码 } } |
然后回过头来看EventBus的findSubscriberMethods方法中的subscriber方法,这个方法是执行订阅操作的。
1 2 3 4 5 6 7 | synchronized ( this ) { //加锁,一次只能进一个线程 for (SubscriberMethod subscriberMethod : subscriberMethods) { //开始订阅,循环向subscriptionsByEventType中添加订阅对象。具体的做法是,根据事件类型取出订阅集合,然后向订阅集合中不断的加入 //订阅,并最终存入subscriptionsByEventType中 subscribe(subscriber, subscriberMethod); } } |
循环遍历subscriberMethods集合,并把subscriber和SubscriberMethod封装成Subscription。并把Subscription添加到subscriptions集合。并以eventType为key,subscriptions为value将其缓存到名字为subscriptionsByEventType的HashMap中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { //从subscriberMethod获取事件类型 Class<?> eventType = subscriberMethod.eventType; //将订阅者对象和订阅方法存入Subscription中 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //先从缓存中取出订阅集合(根据事件类型),如果没有就创建一个 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); 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(); 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); if (subscribedEvents == null ) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); ...省略了一些代码 } |
到此订阅结束。
总结:
1.在EventBus中对各个属性进行初始化、如:HashMap、线程池等
2.获取subscriber的class对象,并通过SubscriberMethodFinder.findSubscriberMethods(subscriberClass)获取到subscriberClass中用subscriber注解标注的方法属性集合(方法、参数类型、线程模型、是否是粘性事件、事件优先级等)。这里面有一个判断条件,先检查缓存中是否有这些方法集合,如果有就直接返回,如果没有就编辑subscriberClass的方法集合选出用subscriber直接标注的方法,并取出方法、参数类型、线程模型、是否是粘性事件、事件优先级等信息,并将其封装为SubscriberMethod对象,然后将SubscriberMethod对象放入List集合返回。
3.对subscriberMethods结合进行遍历,通过subscribe方法进行订阅。在subscribe方法内部会创建一个Subscription对象,并将subscriber对象和SubscriberMethod方法存入。并将Subscription对象加入到CopyOnWriteArrayList集合subscriptions。并以SubscriberMethod.eventType为key,subscriptions为value将数据存入subscriptionsByEventType的HashMap中。到此订阅就结束了。
2.EventBus.getDefault().post(event)使用post方法发送订阅通知
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public void post(Object event) { //从ThreadLocal中取出当前线程中的状态数据 PostingThreadState postingState = currentPostingThreadState.get(); //从当前线程中取出事件队列(其实不是队列,就是一个list集合) List<Object> eventQueue = postingState.eventQueue; //向当前线程的事件队列中加入事件 eventQueue.add(event); if (!postingState.isPosting) { //判断当前线程是不是主线程 postingState.isMainThread = isMainThread(); 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); } } finally { postingState.isPosting = false ; postingState.isMainThread = false ; } } } |
在post内部会创建一个PostingThreadState对象和一个消息队列eventQueue。其中PostingThreadState是一个ThreadLocal对象(其可以在不同的线程之间存储数据,且线程间的数据相互独立)
并对postingState进行初始化,紧接着会调用postSingleEvent方法,并将事件和postingState传递进去。在postSingleEvent方法内部又会调用postSingleEventForEventType方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; //订阅集合 synchronized ( this ) { //根据事件类型从订阅map中取出订阅集合 subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { //循环遍历订阅集合 for (Subscription subscription : subscriptions) { postingState.event = event; postingState.subscription = subscription; boolean aborted = false ; try { //根据线程模型对事件进行分发 postToSubscription(subscription, event, postingState.isMainThread); aborted = postingState.canceled; } finally { postingState.event = null ; postingState.subscription = null ; postingState.canceled = false ; } if (aborted) { break ; } } return true ; } return false ; } |
根据eventClass在subscriptionsByEventType的HashMap中取出Subscriptions集合,循环遍历subscriptions集合并通过postToSubscription方法对事件进行分发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { //从订阅对象中取出线程模型 case POSTING: //默认模式,在哪个线程中订阅就在哪个线程中执行 //具体的分发 invokeSubscriber(subscription, event); break ; case MAIN: //如在主线程(UI线程)发送事件,则直接在主线程处理事件;如果在子线程发送事件,则先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。 if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break ; case MAIN_ORDERED: //无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件 if (mainThreadPoster != null ) { mainThreadPoster.enqueue(subscription, event); } else { // temporary: technically not correct as poster not decoupled from subscriber invokeSubscriber(subscription, event); } break ; case BACKGROUND: //如果在主线程发送事件,则先将事件入队列,然后通过线程池依次处理事件;如果在子线程发送事件,则直接在发送事件的线程处理事件 if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break ; case ASYNC: //无论在那个线程发送事件,都将事件入队列,然后通过线程池处理 asyncPoster.enqueue(subscription, event); break ; default : throw new IllegalStateException( "Unknown thread mode: " + subscription.subscriberMethod.threadMode); } } |
从上面的代码可以看出根据不同的线程模型会执行不同的方法内容。先看下invokeSubscriber(subscription,event)方法都干了啥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** * 具体执行订阅方法的类 * @param subscription 订阅对象 * @param event 事件 */ void invokeSubscriber(Subscription subscription, Object event) { try { //从订阅对象中取出SubscriberMehtod,然后调用其Method方法并执行方法的invoke来完成事件的执行 subscription.subscriberMethod.method.invoke(subscription.subscriber, event); } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException( "Unexpected exception" , e); } } |
上面方法的执行非常的简单,其实就是从subscription中取出subscriberMethod对象,并取出subscriberMethod对象的method方法并执行method方法的invoke函数。执行完这一段之后在subscriber对象中用subscriber注解标注的方法就会执行了。也就是说到此处未知,从订阅到发送到接收就已经执行完了。
上面说的是在那个线程中发送就在哪个线程中接收事件的线程模型。线面说下另外两个,无论如何在主线程中执行和无论如何在子线程中执行。主要看两个类HandlerPoster和BackgroundPoster这个两个为代表讲解一下。
先看HandlerPoster
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class HandlerPoster extends Handler implements Poster { .....省略了一些代码 public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized ( this ) { queue.enqueue(pendingPost); if (!handlerActive) { handlerActive = true ; if (!sendMessage(obtainMessage())) { throw new EventBusException( "Could not send handler message" ); } } } } @Override public void handleMessage(Message msg) { boolean rescheduled = false ; try { long started = SystemClock.uptimeMillis(); while ( true ) { ...省略了一些代码 eventBus.invokeSubscriber(pendingPost); ....省略了一些代码 } |
如果再子线程发送事件,然后想让在在主线程中执行。那么首先就要调用HandlerPoster.enqueue方法,enqueue方法内部会调用sendMessage向主线程Handler发送消息,在Handler的handleMessage内部会接收消息通知,并执行eventBus.invokeSubscriber(pendingPost)。看到这一步其实就明了了,就是通过反射执行方法呗,不同的是执行过程已经切换到主线程了。
再来看一下BackgroundPoster这个类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | final class BackgroundPoster implements Runnable, Poster { ...省略了一些diamante public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized ( this ) { queue.enqueue(pendingPost); if (!executorRunning) { executorRunning = true ; eventBus.getExecutorService().execute( this ); } } } @Override public void run() { try { try { while ( true ) { ...省略了一些代码 eventBus.invokeSubscriber(pendingPost); } } catch (InterruptedException e) { eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted" , e); } } finally { executorRunning = false ; } } } |
从以上的源代码我们可以看出BackgroundPoster实现了Runnable和poster接口,并实现run方法和enqueue方法。在enqueue的内部会调用eventbus的线程池的execute(this)方法运行BackgroundPoster对象的run方法,在run方法内部会调用eventBus.invokeSubscriber(pendingPost)方法,这个方法目的非常明确,通过反射执行subscriber对象中用subscriber注解标注的方法。
总结:
1.在post方法内部对postingThreadState进行初始化并赋值
2.调用postSingleEvent方法,在postSingleEvent方法内部调用postSingleEventForEventType方法,在postSingleEventForEventType方法内部根据eventType从subscriptionsByEventType中取出Subscriptions集合。循环遍历Subscriptions集合,并执行postToSubscription方法。在postToSubscription方法内部会根据不同的现场模型执行对应的方法。如:1.直接执行invokeSubscriber(subscription,eventObj) ,2.通过HandlerPoster.enqueue将执行事件切换到主线程中执行,最终也是会执行invokeSubscriber(pendingPost)方法,3.通过BackgroundPoster.enqueue方法将时间切换到子线程或者线程池中执行,最终会在run方法中执行eventBus.invokeSubscriber(pendingPost)方法。以上三步最终都会调用subscription.subscriberMethod.method.invoke(subscriptions.subscriber,eventObj),完成最终的执行,执行时subscriber注解标注的方法会被执行。
3.我们接下来看下事件的接收,即用subscriber注解标注的方法。其实不用看这个方法,因为这个方法可以自定义只要符合规则就行。主要看一下Subscriber注解的定义和ThreadMode的定义加深对注解和线程模型的理解。
1 2 3 4 5 6 7 8 9 10 11 | @Documented @Retention (RetentionPolicy.RUNTIME) @Target ({ElementType.METHOD}) public @interface Subscribe { //指定订阅事件在哪个线程中运行,默认是POSTING,即在哪个线程中发送就在哪个线程中接收 ThreadMode threadMode() default ThreadMode.POSTING; //粘性事件,默认为false boolean sticky() default false ; //订阅事件执行的优先级 int priority() default 0 ; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /** * EventBus线程模型 */ public enum ThreadMode { /** * 在哪个线程中发送事件就在哪个线程中接收事件 */ POSTING, /** * 如果实在主线程中发送事件就在主线程中处理,如果再子线程中发送事件就把事件先如队列,然后通过handler切换到主线程中处理 */ MAIN, /** * 无论在主线程还是子线程中发送事件,都将事件先入队列,然后通过Handler切换到主线程,依次处理事件。 */ MAIN_ORDERED, /** * 如果再主线程中发送事件,则将事件入队列,在线程池中依次执行。如果在子线程中发送事件,则直接在发送事件的线程中处理事件。 */ BACKGROUND, /** * 无论是在主线程还是在子线程中发送事件,都把时间入队列,通过线程池依次执行 */ ASYNC } |
不多说,注释非常的清晰了。
4.接下来看一下事件是如何取消注册的,即EventBus.getDefault().unRegister(this)
1 2 3 4 5 6 7 8 9 10 11 | public synchronized void unregister(Object subscriber) { List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null ) { for (Class<?> eventType : subscribedTypes) { unsubscribeByEventType(subscriber, eventType); } typesBySubscriber.remove(subscriber); } else { logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null ) { int size = subscriptions.size(); for ( int i = 0 ; i < size; i++) { Subscription subscription = subscriptions.get(i); if (subscription.subscriber == subscriber) { subscription.active = false ; subscriptions.remove(i); i--; size--; } } } } |
注册这块非常的简单就分两步:1.移除typesBySubscriber集合中的对象。2.通过eventType从subscriptionsByEventType中取出Subscriptions集合,然后找到和subscriber相等的Subscription.subscriber,然后将其从集合中移除掉就行了。
总结:再总结一下这个三大流程做一个汇总
1.注册
注册是通过EventBus.getDefault().register(this)来完成的,
a.其首先获取到订阅者subscriber的class对象。
b.通过SubscriberMethodFinder对象的findSubscriberMethod获取订阅者方法集合(List<SubscriberMethod>),在这个方法中首先会根据subscriber.getClass为key检查METHOD_CACHE,Map集合中是否有缓存对象,如果有就直接返回,如果没有就解析subscriber.getClass()对象中用subscribe注解标注的方法,并从中取出Method、参数类型(eventType)、线程模型ThreadMode、是否是粘性事件、事件的优先级,并将这几个值封装到SubscriberMethod中,然后把SubscriberMethod对象存储到List<SubscriberMethod> subscriberMethods集合中,再以subscriber.getClass()为key,subscriberMethods为value存入METHOD_CACHE集合中,最后返回一个List<SubscriberMethod> subscriberMethods的集合。
c.遍历subscriber集合并通过subscribe实现真正的订阅。在subscribe方法中会创建一个Subscription对象,并将subscriber和subscriberMethod存入Subscription对象,然后把Subscription对象存入CopyOnWriteArrayList<Subscription> subscriptions集合,并以subscription.subscriberMethod.eventType为key,subscriptions为value存入subscriptionsByEventType。以subscriber为key,List<Class<?>> subscribedEvents 为value将订阅者和事件类型关联到HashMap<subscriber,eventType> typesBySubscriber集合,到此注册订阅者就全部完成了。
2.发送
发送事件是从EventBus.getDefault().post(obj)开始的
a.在post方法内部会首先初始化PostingThreadState(这个对象用ThreadLocal来存储的)。如:当前线程类型、队列等。然后会调用postSingleEvent方法,在postSingleEvent方法内部又会调用postSingleEventForEventType方法
b.在postSingleEventForEventType方法内部会从subscriptionsByEventType集合中根据eventClass取出Subscriptions集合。然后循环遍历Subscriptions集合,并循环调用postToSubscription方法
c.在postToSubscription方法内部会根据不同的线程模型执行不同的操作,如:MAIN,BACKGROUND等。最终都会调用eventBus.invokeSubscriber()方法,在invokeSubscriber内部会通过反射执行被subscriber注解标注过的方法,如:subscription.subscriberMethod.method.invoke(subscription.subscriber,eventObj).
3.接收
接收方法使用subscriber注解标注的自定义方法,非常简单,不再赘述。
4.取消注册
取消是通过EventBus.getDefault().unRegister(this)
a.首先根据句subscriber对象拿到typesBySubscriber Map集合。并取出List<Class<?> subscriberTypes集合
b.循环遍历subscriberTypes集合,然后以eventTypeClass为key从subscriptionsByEventType集合中获取到subscriptions集合。循环遍历subscriptions集合取出subscription.subscriber==subscriber相等的,然后移除掉缓存。
c.根据subscriber为key,移除掉typesBySubscriber集合中的缓存的eventTypes集合。
到此取消注册也就结束了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
2014-03-10 Android FragmentPagerAdapter翻译
2014-03-10 Android PageAdapter翻译
2014-03-10 Android java.lang.RuntimeException: Unable to instantiate activity ComponentInfo 特殊异常