前面我学习了如何使用EventBus,还有了解了EventBus的特性,那么接下来咱们一块儿来学习EventBus的源码,查看EventBus的源码,看看EventBus给咱们带来什么惊喜以及编程思想。java
这个图咱们从一开始就一直放置在上面了。咱们在来回顾一下,EventBus的官网是怎么定义它的呢?
EventBus是Android和Java的发布/订阅(观察者模式)事件总线。
咱们大概了解了EventBus的构建思想。接下来咱们进入源码学习吧。git
咱们从EventBus的注册开始入手。github
EventBus.getDefault().register(this);
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { //建立了EventBus实例,进入下面的方法 defaultInstance = new EventBus(); } } } return defaultInstance; }
上面的方法是一个双重校验的单例。编程
public EventBus() { this(DEFAULT_BUILDER); //private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder(); }
DEFAULT_BUILDER
是EventBusBuilder.class
实例来建立的,这个类很是重要:使用自定义参数建立EventBus实例,还容许自定义默认EventBus实例,如前面的例子使用索引、配置EventBus的配置&事件的优先级&使用索引(四)等就是经过这个类来实现的,你们能够回顾一下。进入初始化一下必要的参数的构造方法EventBus(EventBusBuilder builder)
,以下设计模式
EventBus(EventBusBuilder builder) { logger = builder.getLogger(); /初始化Logger subscriptionsByEventType = new HashMap<>(); //存储订阅事件的 typesBySubscriber = new HashMap<>(); //存储相关订阅者class列表,key是注册者的对象,value是订阅者的class列表 stickyEvents = new ConcurrentHashMap<>(); //粘性事件 //下面这4个实例就是咱们设置方法``threadMode = ThreadMode.xxx`` //*1 mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); //获取注册者信息索引(添加由EventBus的注释预处理器生成的索引) indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; //初始订阅方法查找器。这个类主要具备查找订阅的方法,继续往下看 subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; //是否有日记订阅,默认true logNoSubscriberMessages = builder.logNoSubscriberMessages;//是否有日记信息,默认 true sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;//是否发送订阅异常事件,默认true sendNoSubscriberEvent = builder.sendNoSubscriberEvent; //是否发送没有订阅事件,默认true throwSubscriberException = builder.throwSubscriberException; //是否抛出异常处理 //默认状况下,EventBus会考虑事件类层次结构(将通知超类的注册者)。 关闭此功能将改善事件的发布。对于直接扩展Object的简单事件类,咱们测量事件发布的速度提升了20%。 eventInheritance = builder.eventInheritance; executorService = builder.executorService; //建立线程池 }
咱们将此段代码逐步分析.
这步主要是进行初始化话一下必要的参数,如代码注解所示。
下面这段代码就是咱们经常使用的@Subscribe(threadMode = ThreadMode.xxx);
初始化。通常经常使用的就是如下4种。数组
mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this);
咱们来看看builder.getMainThreadSupport()
方法返回的是MainThreadSupport
接口,表示为支持Android主线程。
上面的4个线程中都持有 PendingPostQueue
等待发送的队列实例。
由mainThreadSupport.createPoster(this)
建立一个HandlerPoster
而该类继承了Handle
,而且初始化了一个等待发布队列。代码以下。安全
public interface MainThreadSupport { boolean isMainThread(); Poster createPoster(EventBus eventBus); class AndroidHandlerMainThreadSupport implements MainThreadSupport { private final Looper looper; public AndroidHandlerMainThreadSupport(Looper looper) { this.looper = looper; } @Override public boolean isMainThread() { return looper == Looper.myLooper(); } @Override public Poster createPoster(EventBus eventBus) { return new HandlerPoster(eventBus, looper, 10); } } }
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex);
上面代码在这里主要初始化订阅的方法查找器。下面会讲解到它是如何进行订阅方法的。
咱们这这里知道了EventBus初始化,而后相关的实例的建立,接下来我咱们进入到register(this)
方法的调用以下方法。异步
public void register(Object subscriber) { //获取当前注册者对象的Class。 Class<?> subscriberClass = subscriber.getClass(); //经过该注册者的`Class`来获取当前注册者里面由`@Subscriber`注解绑定的方法。 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); //必须在线程同步中进行。 synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
上面的代码表示的是给注册者接收事件。 传递当前所注册的对象,如Activity、Fragment
。async
unregister(Object)
方法,表示解除注册则该订阅者将再也不接收到数据了,若是不进行解除将可能出现内存泄漏。通常在onDestroy
方法解除注册后面会讲解到。 在注册者中拥有必须由@Subscribe
注解的方法。@Subscribe
还容许配置ThreadMode
和优先级、是不是粘性行为。接着,咱们进入List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
方法。ide
//private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>(); //线程安全 List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { //从Map集合中获取订阅方法列表 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); //判断当前获取方法是否为空 if (subscriberMethods != null) { return subscriberMethods; } //经过EventBusBuilder.ignoreGeneratedIndex //是否忽略配置索引,默认是忽略索引 if (ignoreGeneratedIndex) { //1.经过反射获取方法列表 subscriberMethods = findUsingReflection(subscriberClass); } else { //2.经过索引方式获取订阅方法列表 subscriberMethods = findUsingInfo(subscriberClass); } //是否订阅方法为空,若是为空则表示该订阅者里面的方法都不符合EventBus订阅方法的规则 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; } }
咱们逐步分析该段代码。
该段代码经过注册者的类来获取当前dingy的方法列表,若是不为空则直接返回订阅方法。
经过反射来查找订阅方法,若是该方法为空则抛出异常:该订阅者的方法和其超类没有@Subscriber
注解的共有方法(即表示不符合EventBus订阅方法的规则)。若是不为空则存储到ConcurrentHashMap
集合中。
这里的是由ConcurrentHashMap
集合存储是以当前订阅者的class
为key
,而将其由@Subscriber
绑定的方法添加到List
中,,就是集合的value
。必须保持线程安全的,因此这里使用了ConcurrentHashMap
。
findUsingReflection(Class<?> subscriberClass)
,经过反射进行获取List<SubscriberMethod>
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) { FindState findState = prepareFindState();//准备查找状态 findState.initForSubscriber(subscriberClass);// 初始化订阅者信息 while (findState.clazz != null) {//循环获取订阅者的class是否为空 //经过反射获取订阅方法, // 3.该方法下面分析 findUsingReflectionInSingleClass(findState); findState.moveToSuperclass(); //删除超类class } ////获取订阅方法list return getMethodsAndRelease(findState); }
上面的代码主要是经过反射来获取相关的订阅方法,里面由静态内部类FindState
进行管理相关信息,因为上面的方法和下面索引的方法都将调用同一个方法,因此放在下面来将讲解,请看下面信息。
findUsingInfo(Class<?> subscriberClass)
方法,以下。private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState(); //准备查找状态 findState.initForSubscriber(subscriberClass);// 初始化订阅者信息 while (findState.clazz != null) { //循环获取订阅者的class是否为空 findState.subscriberInfo = getSubscriberInfo(findState);//获取获取订阅者信息,这里若是使用添加索引的话,这里将能获取到索引的相关信息。 if (findState.subscriberInfo != null) { //获取订阅方法 SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { //进行等级检查,并存储到Map集合中,该方法checkAdd是FindState.class中的方法 ,key是@Subscriber中参数的class,value是该subscriberMethod.method,也就是@Subscribe中的方法如:public void onMessageEvent(MessageEvent event) if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { //将该订阅方法添加到列表中 findState.subscriberMethods.add(subscriberMethod); } } } else { //3.经过使用反射的方式来获取,和上面忽略索引调用到同一个方法,这里将解析 findUsingReflectionInSingleClass(findState); } //清除父类的方法 findState.moveToSuperclass(); } //获取订阅方法list return getMethodsAndRelease(findState); }
分析本段代码。
首先进入查找的准备状态,经过默认状态池返回状态信息,主要存储的是FindState
实例。主要存储的有订阅者的class、订阅者信息SubscriberInfo
。订阅者@Subscribe
方法列表List<SubscriberMethod>
等.
若是当前订阅者class
不为空,则将获取到订阅者信息。这里分两种状况。
若是使用添加索引的话,getSubscriberInfo(findState)
该方法将获取到订阅信息,若是没有使用索引的话则将调用findUsingReflectionInSingleClass(findState);
该方法来获取信息
//获取订阅方法 SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
因为AbstractSubscriberInfo
类实现了SubscriberInfo
接口,而SimpleSubscriberInfo
继承了AbstractSubscriberInfo
并实现了getSubscriberMethods
方法,代码以下:
本段代码在SimpleSubscriberInfo.class
中。返回订阅方法数组SubscriberMethod[]
。
@Override public synchronized SubscriberMethod[] getSubscriberMethods() { int length = methodInfos.length; SubscriberMethod[] methods = new SubscriberMethod[length]; for (int i = 0; i < length; i++) { SubscriberMethodInfo info = methodInfos[i]; methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode, info.priority, info.sticky); } return methods; }
findUsingReflectionInSingleClass(findState);
经过反射来获取订阅者方法。这个方法有点长,慢慢看。
private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { // This is faster than getMethods, especially when subscribers are fat classes like Activities //该方法代替getMethods()方法,获取该订阅者class所有方法。 methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 methods = findState.clazz.getMethods(); //获取该订阅者class所有方法 findState.skipSuperClasses = true; //设置跳过超类 } for (Method method : methods) { int modifiers = method.getModifiers();//获取修饰符 if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { //经过与运算判断当前的修饰符,是否符合EventBus方法定义 Class<?>[] parameterTypes = method.getParameterTypes(); //获取参数类型 if (parameterTypes.length == 1) { //由于EventBus方法中必须有参数,因此当参数为1时,符合要求 //经过注解的形式@Subscribe获取Subscribe,默认的Subscribe为(priority==0,sticky=false,threadMode=POSTING),就是说ThreadMode为POSTING,粘性为false,优先级为0,若是方法中设置了相应的值,则将是你设置的值。如threadMode=MAIN。 Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); if (subscribeAnnotation != null) { Class<?> eventType = parameterTypes[0]; //获取当前参数的class //进行等级检查,并存储到Map集合中,该方法checkAdd是FindState.class中的方法 ,key是@Subscriber中参数的class,value是该subscriberMethod.method,也就是@Subscribe中的方法如:public void onMessageEvent(MessageEvent event) if (findState.checkAdd(method, eventType)) { // 获取ThreadMode ,如MAIN ThreadMode threadMode = subscribeAnnotation.threadMode(); //将订阅方法添加到列表中 findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { //不符合EventBus订阅方法的规则要求。抛出异常,提示该方法必须是@Subscribe注解,而且须要一个参数 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)) {//是一种非法的@Subscribe方法:必须是公共的,非静态的,非抽象的 String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } }
该段代码主要是获取该注册者的所有方法,并进行筛选出来符合EventBus的订阅方法的规则,经过注解的形式来获取订阅方法,最后添加到查找状态的列表中。
首先获取的是修饰符,参数类型,再经过注解的形式来获取订阅方法。以下注解Subscribe
,若是不符合EventBus相关订阅方法的规则将抛出异常提示,是否在方法上书写了错误的方法。
接下来咱们进入看看@Subscribe
订阅方法是经过注解的形式来设置的。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Subscribe { //ThreadMode ,默认POSTING ThreadMode threadMode() default ThreadMode.POSTING; //粘性事件,默认false boolean sticky() default false; //优先级,默认0 int priority() default 0; }
接下来进入getMethodsAndRelease(FindState 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; //将查找状态器findState,添加到状态池FIND_STATE_POOL中,为下次直接从查找状态池中获取 break; } } } return subscriberMethods; // 返回订阅方法列表 }
上面该方法经过FindState
静态内部类获取了订阅的列表,而后被存储到了ConcurrentHashMap
集合中。而且存储到状态池中,为方便下次读取。而且回收资源。
获取到List<SubscriberMethod>
订阅列表后,再次回到了注册方法中register(Object subscriber)进入到方法subscribe(subscriber, subscriberMethod);
该方法经过循环进行遍历
//这里的参数subscriber表示的是订阅者,如Activity等,subscriberMethod表示订阅方法,该方法就是在subscriber里面 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType; //获取事件类型,也就是参数的class Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //经过事件类型参数class获取CopyOnWriteArrayList<Subscription>列表,该类你们能够研究一下, //是写时复制容器,即当咱们往`CopyOnWriteArrayList`容器添加元素时,先从原有的数组中拷贝一份出来,而后在新的容器作写操做(添加元素),写完以后,再将原来的数组引用指向到新数组的形式存储数据的,它是线程安全的。 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); //添加到Map集合中 } 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);//优先级高的添加添加到CopyOnWriteArrayList容器最前面,只有一个的时候就是添加在第一位了。 break; } } //获取订阅事件的class列表,即订阅方法的参数class列表 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); //存储到Map集合,key是订阅者(即上面传递的Activity对象),value是订阅事件列表 typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); //将该事件类型class添加到订阅事件列表中 判断当前方法是不是粘性的 if (subscriberMethod.sticky) { if (eventInheritance) { //必须考虑eventType的全部子类的现有粘性事件 // 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(); isAssignableFrom(Class<?> cls)方法表示的类型是否能够经过标识转换或经过扩展引用转换为此类对象表示的类型,则返回true if (eventType.isAssignableFrom(candidateEventType)) { Object stickyEvent = entry.getValue(); //将粘性事件添加到订阅者列表中 checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } } else { //将粘性事件添加到订阅者列表中 Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } }
上面的方法中主要是经过获取"事件类型"即订阅方法中的参数class
。而后将其添加到Map集合中,这里用到了CopyOnWriteArrayList
(原理:是写时复制容器,即当咱们往CopyOnWriteArrayList容器添加元素时,先从原有的数组中拷贝一份出来,而后在新的容器作写操做(添加元素),写完以后,再将原来的数组引用指向到新数组的形式存储数据的,它是线程安全的。)
而后进行判断是否设置优先级,遍历并添加到subscriptions
列表中。
经过当前的注册者,获取注册者class列表,并添加到typesBySubscriber
集合中,key
是注册者的class
,如:Activity
,而value
就是订阅方法中的参数class
的列表。这个地方说明了,一个注册者,能够拥有多个订阅事件(方法),将其绑定起来,存储到Map集合中。最后将该参数class添加到subscribedEvents.add(eventType);
列表中。
下面方法是检查粘性事件订阅发送事件方法,以下
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. //这段代码咱们到post发送事件的调用的时候讲解。 postToSubscription(newSubscription, stickyEvent, isMainThread()); } }
postToSubscription
咱们到发送事件POST方法调用时讲解。接下来我进入post
方法,事件发送。此时,咱们回忆一下简介中的图:post()==>EventBus==>将分发到各个订阅事件中
。也就是订阅方法。咱们来看看是如何进行操做的。代码以下
EventBus.getDefault().post(new MessageEvent(message));
经过以上代码我大概的知道,post()
方法里面的参数是一个实体的对象,而该实体就是咱们在订阅方法中的参数实体。你发现了什么了吗?
前边咱们已经分析了,该注册者的订阅方法主要的存储过程,接下来咱们一块儿进入探究吧。方法跟踪进入post()
方法。
/** Posts the given event to the event bus. */ //给订阅事件,发送事件总线 public void post(Object event) { //获取当前线程,即经过ThreadLocal本地线程来管理对应的事件线程,而且初始化发送线程状态PostingThreadState 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; } } }
currentPostingThreadState.get()
方法中咱们知道
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } };
经过ThreadLocal
这里就叫"本地线程"吧,来管理当前的发送线程状态,每一个发送线程将获得对应一个PostingThreadState
,而该PostingThreadState
管理eventQueue
信息,该信息主要存储的是发送事件。
经过eventQueue.add(event)
存储该发送事件之后完成之后,就判断当前的发送事件状态是不是正在发送中,若是还没发送则当该eventQueue
不为为空的时候,进入循环发送该事件,发送完一个就删除一个,直到发送完成为止。
进入方法postSingleEvent(Object event, PostingThreadState postingState)
中。
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; if (eventInheritance) { //查找全部事件类型 List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); 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)); } } }
上面的方法首先获取该事件类型的class
而后传递到lookupAllEventTypes(eventClass)
方法中,经过该方法获取当前发送事件的class
,包括父类、实现的接口等等列表。因此通常状况下会返回当前发送的事件,和Object.class
(注:固然了,若是该事件实现接口的话,也会包括实现的接口的。)列表即List<Class<?>>
,而后进行遍历进行或运算。
咱们先进入lookupAllEventTypes(eventClass)
方法,看看返回的事件类型,而且知道他存储到Map集合中,即key是当前事件class,value是该事件的全部类型,包括父类,接口等。
/** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */ private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) { //private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>(); key是当前事件类型的class,valu则是事件的全部类型,包括父类,接口等。本事例会获得的是MessageEvent.class、和Object.class synchronized (eventTypesCache) { List<Class<?>> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { eventTypes = new ArrayList<>(); Class<?> clazz = eventClass; while (clazz != null) { eventTypes.add(clazz); //添加到列表中 //添加接口 addInterfaces(eventTypes, clazz.getInterfaces()); clazz = clazz.getSuperclass(); //获取父类class } eventTypesCache.put(eventClass, eventTypes); //存储d } return eventTypes; } }
看看方法postSingleEventForEventType(event, postingState, clazz)
,发送事件
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { //经过当前的事件class,获取订阅事件列表 subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { for (Subscription subscription : subscriptions) { //对PostingThreadState进行赋值 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; }
你们是否还记得在注册的时候出现的CopyOnWriteArrayList<Subscription>
在这里就用到了,经过发送事件的class
获取CopyOnWriteArrayList
容器里面的订阅事件信息,包括注册者对象,订阅方法等。而后遍历并进行发送事件。在此方法发布postToSubscription()
事件
/** * subscription:发布订阅的事件处理器 * event:当前发布的事件 * isMainThread:是不是在主线程中 */ private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case POSTING: invokeSubscriber(subscription, event); break; case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case MAIN_ORDERED: 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); } }
好了,这就是以前咱们在注册中有一个地方遗留下的,就是判断是不是粘性状态是调用的方法,你们往回看,就看到了在方法checkPostStickyEventToSubscription
中有调用到该方法。
这里会根据,在方法中所选的threadMode
进行调用,
MAIN
,若是当前是不是UI线程,则会进入到invokeSubscriber(subscription, event);
方法中。不然将调用mainThreadPoster.enqueue(subscription, event);
这个方法将交给HandlerPoster.class
里面的enqueue(Subscription subscription, Object event)
方法,HandlerPoster.class
现实了该接口,移交给handle
完成,你们能够进入HandlerPoster.class
看看,这里就不说了。POSTING
直接调用 invokeSubscriber(subscription, event);
MAIN_ORDERED
若是当前mainThreadPoster
不为空则调用 mainThreadPoster.enqueue(subscription, event);
和MAIN
进入HandlerPoster.class
,反之调用invokeSubscriber(subscription, event);
BACKGROUND
若是当前是主线程,则调用backgroundPoster.enqueue(subscription, event);
,反之调用invokeSubscriber(subscription, event);
ASYNC
,异步方法调用,执行 asyncPoster.enqueue(subscription, event);
,方法进行跟踪,该类有实现了Runnable
接口,而后调用eventBus.invokeSubscriber(pendingPost);
,最终将调用了invoke
方法。void invokeSubscriber(Subscription subscription, Object event) { 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); } }
invoke()
这是一个本地的方法,将调用C/C++的到方法进行发布。最后将进入到订阅方法中。并传递该事件到到订阅的方法中。
好了,这里咱们将post发布事件的方法简单的分析了一下。整个EventBus的分析差很少完成了,可是,咱们还有一点不能忘记就是解除绑定。接下来咱们来看看解除绑定的方法。
onDestroy()
方法中进行解除绑定。代码以下:
EventBus.getDefault().unregister(this);
直接进入unregister(this)
/** Unregisters the given subscriber from all event classes. */ 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()); } }
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */ /** * subscriber:指代当前解除注册的对象如Activity, * eventType:发送的事件类型,post函数的实体对象class */ 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.本篇文章主要对EventBus源码进行简单的分析。主要是进行了观察者模式的一些高级运用。若是你们对观察者模式理解不怎么清楚能够进入这里看看简单的案例观察者模式,内容很是简单。
2.相关的EvenBut的使用,请看以前的内容。如EventBus认识(一)、EventBus的ThreadMode使用以及分析(二)等等。
3.学习本篇文章中能够认识到一些经常使用的类如CopyOnWriteArrayList
、ThreadLocal
等,到时能够深刻研究一下,有助咱们提升。
4.一些编程思想,设计模式值得咱们去学习的,如单例模式EventBus双重校验、建造者模式,EventBus构造器的时候用到,用了初始化各个参数等等。面向接口编程而不针对实现编程。
5.若是有什么问题但愿你们进行指正,好好学习,一块儿进步。