EventBus源码解析(3.1.1版本)
核心思想:
EventBus之所以能在不同线程,不同组件之间进行通信,核心思路是:
1.维护一个单例,使得不同线程,不同组件操作的都是这个整个程序全局的EventBus对象。
2.注册处理方法,将其参数类型、当前所在的类的对象、当前类的class对象对应的方法等等信息保存起来,存放在全局的EventBus中。
使得不同线程,不同组件都可以很轻易拿到这些信息
3.在发送信息的地方,通过发送的参数类型,取到注册时也为此参数类型的方法(可以有多个),通过反射对这些方法进行调用。
基本用法
1.需要触发的地方注册方法
EventBus.getDefault().register(this);
2.注册的处理事件
@Subscribe (ThreadMode = ThreadMode.MAIN)
public void XXX(Event event){
……
}
3.发送事件
EventBus.getDefault().post(event);
getDefault()
- 通过核心思想的分析,可以很容易的猜出这个方法,就是一个单例方法维护整个程序的一个 EventBus 对象。
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
register()
首先应该知道
1.这个方法便是我们核心思想中的第二点,主要是将所有的需要的信息都保存起来
2.为什么要保存起来呢?
答:我们最终要用反射去调用需要触发的方法:
method.invoke(类的对象,参数类型);
为此我们就需要在发送事件的地方,也能取到method、注册类的对象、参数类型。
所以,需要保存到全局的对象中。
正式进入代码
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();//1
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//2
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);//3
}
}
}
- 注释1 处取到了我们反射需要的 注册类的class对象
- 2 处最终返回了 注册类 里注册的 触发方法集合
- 3 处遍历触发方法集合,每个都调用 subscribe 方法将 注册类的对象 、相应的method、参数类型 都关联并保存起来
看看注释3处是怎么保存的(subscribe方法):
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;//2
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//1
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);//2
if (subscriptions == null) {//3
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
……
}
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);//4
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {//5
……
}
}
讲解前不得不先提到几个变量:
1.Subscription
订阅对象
保存了各种订阅信息的对象
2.CopyOnWriteArrayList<Subscription> subscriptions
实现List接口
subscription对象集合
3.private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
Map集合
key:eventType(参数类型);value:CopyOnWriteArrayList(Subscription)
回到代码
* 注释1处,将 subscriber(注册类的对象) 和 subscriberMethod(订阅方法) 作为参数创建一个 Subscription
* 第一个2处将已经保存在订阅方法中的 参数类型eventType 取出。
* 第二个2处以 eventType 为 key 取到 订阅对象集合CopyOnWriteArrayList
* 3处为缓存的使用,如果没有缓存,就以 eventType为key,subscriptions为value保存起来
* 4处将订阅对象以订阅方法优先级保存到 CopyOnWriteArrayList 中
* 5处是对粘性事件的处理,这里不做分析
回到register中的注释2(findSubscriberMethods方法)中:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);//1
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);//3
}
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);//2
return subscriberMethods;
}
}
- 注释1处看看缓存中有没有注册类对应的订阅方法集合,有就直接返回;没有就各种逻辑取到后在2处保存到缓存中
- ignoreGeneratedIndex 一般为 false(调用 getDefault 方法获取单例时为 false)
- 所以,一般执行3
findUsingInfo
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);//1
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();//2
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
findUsingReflectionInSingleClass(findState);//3
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);//4
}
- 1处将 注册类的class对象 赋值到查找工具类 FindState 中:
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
……
}
- 2处不做分析
- 一般执行3处(里面找到订阅方法并将其保存到 findState 的 subscriberMethods 变量 中)
- 4实际上是将 findState 里的 subscriberMethods变量 生成 List集合 返回
注释3处的 findUsingReflectionInSingleClass 方法
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
methods = findState.clazz.getDeclaredMethods();//1
} catch (Throwable th) {
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();//2
if (parameterTypes.length == 1) {//3
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);//4
if (subscribeAnnotation != null) {//4
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();//5
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));//6
}
}
} ……
}
} ……
}
- 注释1处拿到注册类里的所有方法(注册类的class对象 对应的方法)
- 遍历,在2处反射拿到每个方法的参数
- 3处过滤掉所有参数不是1个的方法(说明我们的订阅方法参数应该定义为1个)
- 第一个4处反射拿到 Subscribe 注解,第二个4处判断如果注释不为空,则找到我们的订阅方法
- 5拿到注解里声明的参数 threadMode
- 6用方法(method)、方法类型(eventType)、注解声明的线程模型(ThreadMode)等参数生成一个订阅方法对象(SubscriberMethod)。再添加到 findState 的订阅方法集合中。
然后回到findUsingInfo的注释4处
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
……
return subscriberMethods;
}
- 将 findState 的订阅方法集合生成新的 list 返回
post()
首先应该知道
这个方法是核心思想里的第三点,主要是通过参数类型获得对应的method,最后通过反射进行调用
正式进入代码
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();//1
List<Object> eventQueue = postingState.eventQueue;//2
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);//3
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
- 1处的 PostingThreadState 里保存了事件队列和线程状态信息。
- 2处将事件队列取出,再把事件添加进去
- 3处将队列中的事件依次由 postSingleEvent 方法处理,每次都将list第0个位置的事件移除并传入,就可以实现队列的“先进先出”的效果。
postSingleEvent
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);//1
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);//2
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
……
}
}
- eventInheritance 表示是否向上查找事件的父类,默认为true
- true时,执行1处代码,也即是通过 lookupAllEventTypes 找到所有的父类事件存在list中
- 再对 list 里的所有事件逐一进行 postSingleEventForEventType 处理
这里有什么意义呢:
假如,post(new A());
class A extends B implement C{}
那么如果在一个类中注册了 void xxx(A a){}、 void xxx(B b){}、void xxx(C c){} 三个方法
post一次,这三个方法都会触发。
postSingleEventForEventType
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);//1
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);//2
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
首先,确认下三个参数的意思:
event: post 时传入的事件参数,最终当做反射invoke(,)传入的第二个参数
postingState: 保存事件队列和线程状态信息
eventClass: 事件和其父类对应的 class 对象,用来取到 register 时保存在 map 中对应的订阅方法1处通过 key(事件的class对象) 从执行 register 过程中维护的 map 中取到对应的 subscriptions(订阅对象集合)
- 随之遍历,将 event 和 subscription 传给 postingState
- 2处为核心处理方法
postToSubscription
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {//1
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
if (mainThreadPoster != null) {
……
} else {
……
}
break;
case BACKGROUND:
if (isMainThread) {
……
} else {
……
}
break;
case ASYNC:
……
default:
……
}
}
首先明确下参数:
subscription:订阅对象,包含了注册的类的对象、订阅方法等信息
event:事件参数
isMainThread:发送时所在的线程是否为主线程。(通过Looper.getMainLooper == Looper.myLooper()判断)1处,线程模型为 MAIN 时(哪个线程触发事件)。判断发送时所在的线程是否是主线程
- 如果是,则执行 invokeSubscriber ,若不是,则通过 mainThreadPoster 将订阅事件添加到主线程队列中。(MainThreadPoster 本质是一个 Handler,通过 Handler 将订阅方法切换到主线程执行)
invokeSubscriber
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);//1
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
- 1处,很明显,是通过反射调用订阅方法,传入类的对象,以及事件参数。
拓展
- 因为EventBus是通过参数类型判断哪个方法触发。
- 那么我们如果在同一个类中注册名字不同,但是参数相同的两个方法,post这个参数一次,这两个方法都会被调用。