平面设计图案/无锡优化网站排名
EventBus 3.1.1源码分析
- 前言
- EventBus构造方法
- 订阅者注册
- 查找订阅者方法
- 注册过程
- 发送事件
- 订阅者取消注册
前言
EventBus 是一款在 Android 开发中经常使用的发布/订阅事件总线框架,将事件的接收者和发送者分开;简化了组件之间的通信,使用简单、效率高、体积小!由于经常使用到,所以我们深入理解该框架的原理就很有必要了,下面我们就来分析一下EventBus原理。
EventBus构造方法
大家都知道当我们在使用EventBus时,首先会调用EventBus.getDefault()方法来获取EventBus的实例。那我们来看一下getDefault()方法,代码如下:
/** Convenience singleton for apps using a process-wide EventBus instance. */public static EventBus getDefault() {if (defaultInstance == null) {synchronized (EventBus.class) {if (defaultInstance == null) {defaultInstance = new EventBus();}}}return defaultInstance;}
这是一个双重检查模式单例模式。
接下来是EventBus构造方法,代码如下:
/*** Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a* central bus, consider {@link #getDefault()}.*/public EventBus() {this(DEFAULT_BUILDER);}EventBus(EventBusBuilder builder) {logger = builder.getLogger();subscriptionsByEventType = new HashMap<>();typesBySubscriber = new HashMap<>();stickyEvents = new ConcurrentHashMap<>();mainThreadSupport = builder.getMainThreadSupport();mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;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;executorService = builder.executorService;}
这里DEFAULT_BUILDER是默认的EventBusBuilder:
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
这里调用了EventBus的另外一个构造方法,采用了建造者模式,通过构造EventBusBuilder来配置EventBus。
订阅者注册
获取到EventBus的实例以后就调用register(this)方法将订阅者注册到EventBus中,register()方法代码如下:
public void register(Object subscriber) {Class<?> subscriberClass = subscriber.getClass();List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//得到一个SubscriberMethod的集合,就是传进来的订阅者的所有订阅方法synchronized (this) {for (SubscriberMethod subscriberMethod : subscriberMethods) {//遍历订阅者的订阅方法来完成订阅者的注册操作subscribe(subscriber, subscriberMethod);}}}
register方法做了两件事:一件事是查找订阅者的订阅方法,另一件事是订阅者的注册。
SubscriberMethod类主要用来保存订阅方法的Method对象、线程模式、事件类型、优先级、是否是黏性事件等属性。
public class SubscriberMethod {final Method method;final ThreadMode threadMode;final Class<?> eventType;final int priority;final boolean sticky;/** Used for efficient comparison */String methodString;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;}........其他方法........
}
查找订阅者方法
接下来看看findSubscriberMethods(subscriberClass)方法代码:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);//从缓存中查找是否有订阅方法的集合if (subscriberMethods != null) {//如果找到就return return subscriberMethods;}//如果缓存中没有,则根据 ignoreGeneratedIndex属性的值来选择采用何种方法来查找订阅方法的集合//ignoreGeneratedIndex 的默认值是 false,可以通过EventBusBuilder来设置它的值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;}}
ignoreGeneratedIndex 属性表示是否忽略注解器生成的 MyEventBusIndex,具体可以看官网:http://greenrobot.org/eventbus/documentation/subscriber-index/
项目中经常通过EventBus单例模式来获取默认的EventBus对象,也就是ignoreGeneratedIndex为false的情况,这种情况调用了findUsingInfo(subscriberClass)方法,代码如下:
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {FindState findState = prepareFindState();findState.initForSubscriber(subscriberClass);while (findState.clazz != null) {findState.subscriberInfo = getSubscriberInfo(findState);//获取订阅者信息if (findState.subscriberInfo != null) {//如果我们通过EventBusBuilder配置了MyEventBusIndex,便会获取到subscriberInfoSubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();//得到订阅方法相关的信息for (SubscriberMethod subscriberMethod : array) {if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {findState.subscriberMethods.add(subscriberMethod);}}} else {//没有配置MyEventBusIndexfindUsingReflectionInSingleClass(findState);//将订阅方法保存到findState中}findState.moveToSuperclass();}return getMethodsAndRelease(findState);//对findState做回收处理并返回订阅方法的List集合}
在开始查找订阅方法的时候并没有忽略注解器为我们生成的索引 MyEventBusIndex。
如果我们通过EventBusBuilder配置了MyEventBusIndex,便会获取subscriberInfo(这个参考上面ignoreGeneratedIndex为true的情况所调用的方法findUsingReflection(subscriberClass));
没有配置MyEventBusIndex便会执行findUsingReflectionInSingleClass(findState)方法;
最后再通过getMethodsAndRelease(findState)方法对findState做回收处理并返回订阅方法的List集合,这里贴一下getMethodsAndRelease(findState)方法代码:
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);findState.recycle();synchronized (FIND_STATE_POOL) {for (int i = 0; i < POOL_SIZE; i++) {if (FIND_STATE_POOL[i] == null) {FIND_STATE_POOL[i] = findState;break;}}}return subscriberMethods;}
默认情况下是没有配置MyEventBusIndex的,所以就会调用findUsingReflectionInSingleClass(findState)方法,代码如下:
private void findUsingReflectionInSingleClass(FindState findState) {Method[] methods;try {// This is faster than getMethods, especially when subscribers are fat classes like Activitiesmethods = findState.clazz.getDeclaredMethods();//通过反射来获取订阅者中的方法} catch (Throwable th) {// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149methods = findState.clazz.getMethods();findState.skipSuperClasses = true;}for (Method method : methods) {int modifiers = method.getModifiers();//根据方法的类型、参数和注解来找到订阅方法。找到订阅方法后将订阅方法的相关信息保存到findState中。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)) {ThreadMode threadMode = subscribeAnnotation.threadMode();findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()));}}} 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");}}}
注册过程
上面register方法里面遍历SubscriberMethod对所有的订阅方法进行注册,调用了subscribe(subscriber, subscriberMethod)方法,代码如下:
// Must be called in synchronized blockprivate void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {Class<?> eventType = subscriberMethod.eventType;//根据subscriber(订阅者)和subscriberMethod(订阅方法)创建一个Subscription(订阅对象)Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//根据eventType(事件类型)获取Subscriptions(订阅对象集合)CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);if (subscriptions == null) {//如果Subscriptions为null则重新创建,并将Subscriptions根据eventType保存在subscriptionsByEventType中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);//通过subscriber获取subscribedEvents事件类型集合if (subscribedEvents == null) {subscribedEvents = new ArrayList<>();//为空重新创建对象typesBySubscriber.put(subscriber, subscribedEvents);//根据subscriber将subscribedEvents存储在typesBySubscriber集合中}subscribedEvents.add(eventType);//将eventType添加到subscribedEvents中if (subscriberMethod.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>).//从stickyEvents事件保存队列中取出该事件类型的事件发送给当前订阅者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);}}}
subscribe()方法主要就是做了两件事:
1、将Subscriptions根据eventType封装到subscriptionsByEventType中,将subscribedEvents根据subscriber封装到typesBySubscriber中;
2、对黏性事件的处理。
发送事件
我们通过post方法来对事件进行发送,所以我们看一下post()方法源码:
/** Posts the given event to the event bus. */public void post(Object event) {PostingThreadState postingState = currentPostingThreadState.get();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;}}}
PostingThreadState 保存事件队列和线程状态信息,currentPostingThreadState.get()方法获取到PostingThreadState 对象,currentPostingThreadState代码如下:
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {@Overrideprotected PostingThreadState initialValue() {return new PostingThreadState();}};
上面从PostingThreadState对象中取出事件队列,然后再将当前的事件插入事件队列;通过postSingleEvent(eventQueue.remove(0), postingState)方法处理和移除该事件,代码如下:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {Class<?> eventClass = event.getClass();boolean subscriptionFound = false;//eventInheritance 表示是否向上查找事件的父类,它的默认值为 true,可以通过在EventBusBuilder中进行配置if (eventInheritance) {List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);//找到所有的父类事件并存在List中int countTypes = eventTypes.size();for (int h = 0; h < countTypes; h++) {Class<?> clazz = eventTypes.get(h);subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);//事件挨个处理}} else {subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);}if (!subscriptionFound) {//找不到事件的处理方式if (logNoSubscriberMessages) {logger.log(Level.FINE, "No subscribers registered for event " + eventClass);}if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&eventClass != SubscriberExceptionEvent.class) {post(new NoSubscriberEvent(this, event));}}}
接下来我们看看postSingleEventForEventType()方法的代码:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {CopyOnWriteArrayList<Subscription> subscriptions;synchronized (this) {subscriptions = subscriptionsByEventType.get(eventClass);//同步取出该事件对应的Subscriptions订阅对象集合}if (subscriptions != null && !subscriptions.isEmpty()) {//遍历Subscriptions,将事件 event 和对应的 Subscription(订阅对象)传递给postingStatefor (Subscription subscription : subscriptions) postingState.event = event;postingState.subscription = subscription;boolean aborted = false;try {postToSubscription(subscription, event, postingState.isMainThread);//调用postToSubscription方法对事件进行处理。aborted = postingState.canceled;} finally {postingState.event = null;postingState.subscription = null;postingState.canceled = false;}if (aborted) {break;}}return true;}return false;}
接下来看postToSubscription(subscription, event, postingState.isMainThread)方法代码:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {//取出订阅方法的threadMode,根据threadMode来分别处理switch (subscription.subscriberMethod.threadMode) {// 默认的线程模式,在那个线程发送事件就在那个线程处理事件case POSTING:invokeSubscriber(subscription, event);break;// 在主线程处理事件case MAIN:if (isMainThread) {invokeSubscriber(subscription, event);// 如果在主线程发送事件,则直接在主线程通过反射处理事件} else {// 如果是在子线程发送事件,则将事件入队列,通过Handler切换到主线程执行处理事件mainThreadPoster.enqueue(subscription, event);}break;// 无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。case MAIN_ORDERED:if (mainThreadPoster != null) {mainThreadPoster.enqueue(subscription, event);} else {// temporary: technically not correct as poster not decoupled from subscriberinvokeSubscriber(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);}}
根据threadMode来分别处理。如果threadMode是MAIN,提交事件的线程是主线程,则通过反射直接运行订阅的方法;若其不是主线程,则需要mainThreadPoster 将我们的订阅事件添加到主线程队列中。mainThreadPoster是HandlerPoster类的一个实例,继承自Handler,通过Handler将订阅方法切换到主线程执行,看下该类的主要实现,代码如下:
public class HandlerPoster extends Handler implements Poster {private final PendingPostQueue queue;private final int maxMillisInsideHandleMessage;private final EventBus eventBus;private boolean handlerActive;protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {super(looper);this.eventBus = eventBus;this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;queue = new PendingPostQueue();}public void enqueue(Subscription subscription, Object event) {// 用subscription和event封装一个PendingPost对象PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);synchronized (this) {queue.enqueue(pendingPost);// 加入队列if (!handlerActive) {handlerActive = true;// 发送开始处理事件的消息,handleMessage()方法将被执行,完成从子线程到主线程的切换if (!sendMessage(obtainMessage())) {throw new EventBusException("Could not send handler message");}}}}@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);// 进一步处理pendingPostlong timeInMethod = SystemClock.uptimeMillis() - started;if (timeInMethod >= maxMillisInsideHandleMessage) {if (!sendMessage(obtainMessage())) {throw new EventBusException("Could not send handler message");}rescheduled = true;return;}}} finally {handlerActive = rescheduled;}}
}
订阅者取消注册
取消注册就调用unregister()方法,代码如下所示:
/** Unregisters the given subscriber from all event classes. */public synchronized void unregister(Object subscriber) {List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);//通过subscriber找到subscribedTypes事件类型集合if (subscribedTypes != null) {for (Class<?> eventType : subscribedTypes) {unsubscribeByEventType(subscriber, eventType);//遍历 subscribedTypes}typesBySubscriber.remove(subscriber);//将subscriber对应的eventType从 typesBySubscriber中移除} else {logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());}}
接下来看unsubscribeByEventType(subscriber, eventType)方法,代码如下:
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {//通过eventType来得到对应的Subscriptions订阅对象集合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);//如果Subscription(订阅对象)的subscriber(订阅者)属性等于传进来的subscriber,则从Subscriptions中移除该Subscriptionif (subscription.subscriber == subscriber) {subscription.active = false;subscriptions.remove(i);//移除该Subscriptioni--;size--;}}}}
以上就是EventBus的源码分析。