本文主要是介绍EventBus事件分发框架解读,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
全局框架解析:Trinea的EventBus 源码解析
以下是一些具体过程的分析,最好可以先学习上面的链接内容:
下面的方法是注册最终调用的方法:
private synchronized void register(Object subscriber, boolean sticky, int priority) {List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod, sticky, priority);}}
1.通过以下方法获取当前订阅者(就是注册的当前类)中所有的事件响应方法(这些响应方法就是该类中的onEvent(),onEventMainThread(),onEventBackgroundThread(),onEventAsync()这些方法),遍历该类中的所有方法,并将这些方法封装到一个集合中,然后以订阅者的类名为key,响应事件的方法集合为value存到一个用作缓存的hashmap中。下次遍历的时候会先通过key获得已经缓存的方法集合,存在就不会重新遍历。(具体参考源码流程)
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
2.接着循环第一步找到的所有的事件响应方法的集合,并执行subscribe方法:
for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod, sticky, priority);}
具体方法流程:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {Class<?> eventType = subscriberMethod.eventType;CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);if (subscriptions == null) {subscriptions = new CopyOnWriteArrayList<Subscription>();subscriptionsByEventType.put(eventType, subscriptions);} else {if (subscriptions.contains(newSubscription)) {throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "+ eventType);}}// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)// subscriberMethod.method.setAccessible(true);int size = subscriptions.size();for (int i = 0; i <= size; i++) {if (i == size || newSubscription.priority > subscriptions.get(i).priority) {subscriptions.add(i, newSubscription);break;}}List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);if (subscribedEvents == null) {subscribedEvents = new ArrayList<Class<?>>();typesBySubscriber.put(subscriber, subscribedEvents);}subscribedEvents.add(eventType);if (sticky) {if (eventInheritance) {// Existing sticky events of all subclasses of eventType have to be considered.// Note: Iterating over all events may be inefficient with lots of sticky events,// thus data structure should be changed to allow a more efficient lookup// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();for (Map.Entry<Class<?>, Object> entry : entries) {Class<?> candidateEventType = entry.getKey();if (eventType.isAssignableFrom(candidateEventType)) {Object stickyEvent = entry.getValue();checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}} else {Object stickyEvent = stickyEvents.get(eventType);checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}}
如果通过subscriptionsByEventType.get(eventType)来获取以该事件类型为key的订阅信息集合,如果为null,就会往subscriptionsByEventType的map中添加以事件类型为key,一个存放订阅信息的空集合为value,如下:
if (subscriptions == null) {subscriptions = new CopyOnWriteArrayList<Subscription>();subscriptionsByEventType.put(eventType, subscriptions);}
之后通过一个订阅信息的优先级高低,加入到subscriptions集合中,优先级高的放在集合的前面,比如集合中有三个信息优先级分别为4,2,1;现在进来一个优先级为3的,当i=1的时候,由于3的优先级比2高,所以在集合的第一项中加加入了优先级为3的信息,所以现在里面的顺序应该为4,3,2,1.
int size = subscriptions.size();for (int i = 0; i <= size; i++) {if (i == size || newSubscription.priority > subscriptions.get(i).priority) {subscriptions.add(i, newSubscription);break;}}
然后通过typesBySubscriber.get(subscriber)来获取以该类(就是订阅者)为key的所有响应事件的集合,如果为null就会往typesBySubscriber的map中添加以订阅者为key,一个存放该类中所有相应事件的空集合为value,然后再把响应事件添加到事件集合中如下:
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);if (subscribedEvents == null) {subscribedEvents = new ArrayList<Class<?>>();typesBySubscriber.put(subscriber, subscribedEvents);}subscribedEvents.add(eventType);
如果注册的不是sticky事件,就不会进行下面的判断,否则就会进入下面的判断:
if (sticky) {if (eventInheritance) {// Existing sticky events of all subclasses of eventType have to be considered.// Note: Iterating over all events may be inefficient with lots of sticky events,// thus data structure should be changed to allow a more efficient lookup// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();for (Map.Entry<Class<?>, Object> entry : entries) {Class<?> candidateEventType = entry.getKey();if (eventType.isAssignableFrom(candidateEventType)) {Object stickyEvent = entry.getValue();checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}} else {Object stickyEvent = stickyEvents.get(eventType);checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}
如果注册的是sticky事件,则会试图从stickyEvents的map中获取所有的sticky事件,通过eventType.isAssignableFrom(candidateEventType)判断注册的该事件是否已经在其他类注册过,如果注册过,就会调用下面的方法吧事件post到相应的队列中去或者直接调用(前提是之前已经通过post标记为sticky的事件到stickyEvents中):
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {if (stickyEvent != null) {// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)// --> Strange corner case, which we don't take care of here.postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());}}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {switch (subscription.subscriberMethod.threadMode) {case PostThread:invokeSubscriber(subscription, event);break;case MainThread:if (isMainThread) {invokeSubscriber(subscription, event);} else {mainThreadPoster.enqueue(subscription, event);}break;case BackgroundThread: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);}}
MainThread:在主线程处理响应事件的方法,如果post在主线程,直接调用事件响应的方法,如果post在子线程,就会先把响应事件通过 mainThreadPoster.enqueue(subscription, event),加入到在HandlerPoster中维护的一个PendingPostQueue队列中:
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");}}}}
由于HandlerPoster是继承Handler,并且绑定了主线程,所以在通过sendMessage(obtainMessage())发送通知,收到通知后就会从PendingPostQueue队列中拿出事件响应方法,并调用:
@Overridepublic void handleMessage(Message msg) {boolean rescheduled = false;try {long started = SystemClock.uptimeMillis();while (true) {PendingPost pendingPost = queue.poll();if (pendingPost == null) {synchronized (this) {// Check again, this time in synchronizedpendingPost = queue.poll();if (pendingPost == null) {handlerActive = false;return;}}}eventBus.invokeSubscriber(pendingPost);long timeInMethod = SystemClock.uptimeMillis() - started;if (timeInMethod >= maxMillisInsideHandleMessage) {if (!sendMessage(obtainMessage())) {throw new EventBusException("Could not send handler message");}rescheduled = true;return;}}} finally {handlerActive = rescheduled;}}
BackgroundThread:在子线程中执行事件响应的方法(只有一个子线程,就是加入到子线程中的事件存放在队列中安顺序执行)。如果post在主线程,就通过backgroundPoster.enqueue(subscription, event)加入到在BackgroundPoster中维护的一个PendingPostQueue队列中:
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);}}}
由于BackgroundPoster是继承Runnable接口的线程对象,然后通过eventBus.getExecutorService().execute(this)将该线程对象加入到线程池中运行,在run方法中就是从队列PendingPostQueue中拿出一个分装了事件响应方法的PendingPost对象,接着通过eventBus.invokeSubscriber(pendingPost)调用事件响应方法,这里通过executorRunning这个标记来辨别前面的事件是否执行完,如果前一个事件还没有执行完毕,又加入了一个事件,则事件先会存放在队列中,run方法在执行完第一个事件的时候接着会从队列中取出第二个方法继续执行,所以就相当于通过eventBus.getExecutorService()创建的newCachedThreadPool线程池中只有一个工作线程在执行当前的线程对象:
@Overridepublic void run() {try {try {while (true) {PendingPost pendingPost = queue.poll(1000);if (pendingPost == null) {synchronized (this) {// Check again, this time in synchronizedpendingPost = queue.poll();if (pendingPost == null) {executorRunning = false;return;}}}eventBus.invokeSubscriber(pendingPost);}} catch (InterruptedException e) {Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);}} finally {executorRunning = false;}}
如果post在子线程,则直接通过invokeSubscriber(subscription, event)调用事件响应方法。
Async:在子线程中执行事件响应方法()。通过Executors.newCachedThreadPool()来获得一个线程池:
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}
然后通过 asyncPoster.enqueue(subscription, event)加入到AsyncPoster维护的一个PendingPostQueue队列中,然后每enqueue一次,就调用 eventBus.getExecutorService().execute(this)来执行将当前线程对象加入到线程池中:
public void enqueue(Subscription subscription, Object event) {PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);queue.enqueue(pendingPost);eventBus.getExecutorService().execute(this);}
然后通过run方法从队列中拿出事件,并调用:
@Overridepublic void run() {PendingPost pendingPost = queue.poll();if(pendingPost == null) {throw new IllegalStateException("No pending post available");}eventBus.invokeSubscriber(pendingPost);}
注意:通过registerSticky(Object subscriber)注册前提是在某个类中已经用postSticky(Object event)将某事件提交到stickyEvents中,以至于stickyEvents中存在相同的事件类型,这样才会触发用registerSticky(Object subscriber)注册的类中相应的事件,如果没有提交过则和register(Object subscriber)效果一样。一个类只能注册一次(这里的一个类用内存地址区分)。
其实这个框架是类似于Handler框架。
(一般用于跨线程局部通讯,放在Application的Handler可以实现跨线程全局通信)Handler是初始化在哪个线程,那么消息的处理就在哪个线程,而不去管发送消息的时候在哪个线程,但是handler只适用一对一或者多对一的更新,就是最后只有一处地方可以接受并处理消息;
(全局通信,可以跨进程,线程)Broadcast可以进行全局通信,不管在哪发送,但是接受者一般在主线程执行,只要接受者接受到匹配action的广播,就会处理相应的事件,但是Broadcast可以使用一对多或者多对一的更新,需要在多处跟新数据时可以使用,同时存在可以停留消息的功能。
(跨线程全局通信)EventBus是通过注册类的方法名来确定最后事件处理在哪个线程,也同样不管消息发送在哪个线程,相当于提供了一个全局的handler通信对象,但同时具备了Broadcast消息停留的功能,以及多对一和一对多的更新的功能。
对比:相比之下三者之间的功能Broadcast>EventBus>Handler
这篇关于EventBus事件分发框架解读的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!