工欲善其事,必先利其器。要想非常好的将EventBus运用到项目的实践当中去,就必须能够对其框架的内部的机制有很好的理解。So,就有了下面的系列文章。
整个的EventBus框架分为两个包,22个类。包名分别是de.greenrobot.event与de.greenrobot.event.util。很显然,一个是框架的核心代码包,一个是其辅助作用的包,即工具类的集合。在de.greenrobot.event框架下一共有14个类,按照功能,可以大致分为这样几个方面:1)主进程与后台进程处理事件的真正工作者,包括:AsyncPoster、BackgroundPoster以及HandlerPoster。2)围绕整个框架的主题所涉及到的几个类,包括:EventBus、EventBusBuilder以及EventBusException。3)围绕订阅事件的对象Subscriber所需要的几个类,包括:NoSubscriberEvent、SubscriberExceptionEvent、SubscriberMethod以及SubscriberMethod。4)事件消息与事件消息队列相关的类,包括:PendingPost与PendingPostQueue。6)工具包不再一一说明。
1、详细讲解主进程与后台进程处理事件的真正工作者
AsyncPoster实际上是异步的处理事件消息的队列,在这个类中,所涉及到两个成员变量,分别是事件消息队列与主框架Bus。AsyncPoster实现Runnable的接口,其工作正如其Run方法中所体现的那样,从消息队列中取出消息,交给Bus进行触发。同时它还有一个将事件投放到事件队列中的功能。核心方法如下:
PendingPost pendingPost = queue.poll(); if(pendingPost == null) { throw new IllegalStateException("No pending post available"); } eventBus.invokeSubscriber(pendingPost);
BackgroundPoster整体代码与AsyncPoster非常的类似,但是与其不同的是其run方法中是一个while的循环,在当前的事件队列不是空的情况下,会一直从事件的队列中获取事件并且交给Bus去触发。核心代码如下:
try { try { while (true) { PendingPost pendingPost = queue.poll(1000); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = 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; }HandlerPoster与上面两个同样是处理事件,但类型不同,HandlerPoster对应的是Handler。其余的功能上与BackgroundPoster保持一致。核心代码如下:
boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); while (true) { PendingPost pendingPost = queue.poll(); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = 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; }
EventBus无疑是一个核心,首先从构造函数来分析与猜测其大致的功能:1)初始化一个基于事件类型所分类的订阅对象的HashMap 2)通过订阅者所划分的类型的HashMap 3)初始化一个粘性事件所对应的一个ConcurrentHashMap 4)初始化三个任务的执行的对象 5)初始化搜索订阅者方法的对象。 6)相关的日志与异常所对应的布尔值的初始化 7)初始化一个线程池。
其中我们需要关注的方法是subscribe ,也就是具体体现了一个事件是如何被订阅的,其核心代码如下
//订阅方法的事件类型 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); //强制方法必须是public的类型 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) { Object stickyEvent; synchronized (stickyEvents) { stickyEvent = stickyEvents.get(eventType); } 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()); } }还需要关心的是一个方法是如何被触发的,其方法是invokeSubscriber,对应的核心代码如下:
try { subscription.subscriberMethod.method.invoke(subscription.subscriber, event); } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); }
EventBusBuilder可以说是EventBus的配置项,具体的配置属性可以从其成员变量中看出 1、创建默认线程池 2、相关日志打印的开关 3、部分Class 允许跳过检测
3、详细讲解围绕订阅事件的对象Subscriber所需要的几个类
SubscriberExceptionEvent正如其名称一样,它是由EventBus所提交的一个事件,当异常出现在一个订阅者的事件的处理中。
SubscriberMethod对应的是触发订阅者的方法,同样从其构造方法来猜测其大致的功能,1)成员变量Method的赋值 2)当前的事件在哪种线程的模式先工作,线程模式ThreadMode具体可以看见代码的注释。 3)触发的事件的类型
SubscriberMethodFinder的功能是寻找订阅者的哪些方法会被触发,还是用到了较多的反射机制,核心代码如下:
Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { String methodName = method.getName(); //是否是方法名以onEvent开头 if (methodName.startsWith(ON_EVENT_METHOD_NAME)) { int modifiers = method.getModifiers(); //强制性是public的类型 并且不允许在忽略的类型的方法的里面 if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1) { //去除其中的参数 //通过函数名 决定在哪种线程中进行运行 String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length()); ThreadMode threadMode; if (modifierString.length() == 0) { threadMode = ThreadMode.PostThread; } else if (modifierString.equals("MainThread")) { threadMode = ThreadMode.MainThread; } else if (modifierString.equals("BackgroundThread")) { threadMode = ThreadMode.BackgroundThread; } else if (modifierString.equals("Async")) { threadMode = ThreadMode.Async; } else { if (skipMethodVerificationForClasses.containsKey(clazz)) { continue; } else { throw new EventBusException("Illegal onEvent method, check for typos: " + method); } } Class<?> eventType = parameterTypes[0]; methodKeyBuilder.setLength(0); methodKeyBuilder.append(methodName); methodKeyBuilder.append('>').append(eventType.getName()); String methodKey = methodKeyBuilder.toString(); if (eventTypesFound.add(methodKey)) { // Only add if not already found in a sub class subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); } } } else if (!skipMethodVerificationForClasses.containsKey(clazz)) { Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "." + methodName); } } } clazz = clazz.getSuperclass();
OK,相信介绍到这里相信童鞋们对EventBus这种框架的代码以及有一定的了解了吧!希望这篇文章对大家有帮助,这样也不辜负我的文字啦~