1秋柄、EventBus方法注冊
先從注冊的對象中找到對應(yīng)的方法
1)先從對外聲明的方法找弛作,如果發(fā)生異常,再找全部方法
找全部方法的時候會設(shè)置變量findState.skipSuperClasses = true; 這樣就不用再次找父類的方法了
try {
// This is faster than getMethods, especially when subscribers are fat classes
like Activities
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
try {
methods = findState.clazz.getMethods();
2)方法必須是public修飾的华匾,并且不能是抽象 靜態(tài)的方法(可設(shè)置讓其報出異常)
3)方法必須是Subscribe注解修飾映琳,并且方法的參數(shù)必須是有且只有1個(可設(shè)置讓其報出異常)
4)找完本類后,通持├回去找對應(yīng)的父類的方法萨西,(java和android這樣的父類不包括)
5)負責(zé)查找方法的類是FindState,這個用到了享元模式旭旭,方便對象的復(fù)用谎脯,每次用完會把對象的狀態(tài)置為原值,并放入緩存池中
6)如果是粘性方法持寄,會取出對應(yīng)的粘性事件源梭,發(fā)給注冊的這個方法
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
try {
methods = findState.clazz.getMethods();
} catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
String msg = "Could not inspect methods of " + findState.clazz.getName();
if (ignoreGeneratedIndex) {
msg += ". Please consider using EventBus annotation processor to avoid reflection.";
} else {
msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
}
throw new EventBusException(msg, error);
}
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
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");
}
}
}
二、發(fā)送事件
發(fā)送消息分為發(fā)送正常事件和發(fā)送粘性事件:
發(fā)送粘性事件和發(fā)送正常事件的區(qū)別在于稍味,把粘性事件放到粘性集合中放一份废麻,然后調(diào)用發(fā)送正常事件的方法
1、 public void post(Object event)
2模庐、 public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
發(fā)送事件分為以下幾步:
1烛愧、把發(fā)送的事件放入待發(fā)送的集合中
2、找到這個事件的所有父類和實現(xiàn)的接口(允許事件繼承關(guān)系的話掂碱,可通過變量設(shè)置)
3怜姿、遍歷第2步中找到的所有事件,根據(jù)事件找到對應(yīng)的方法疼燥,進行執(zhí)行
根據(jù)事件找方法的操作為從map集合中找沧卢,key為這個事件的類型,value為存放了所有監(jiān)聽這個事件的方法的集合
4醉者、方法執(zhí)行中但狭,涉及到在哪個線程執(zhí)行的問題
EvenBus中方法所在的線程分為五種:
1)POSTING 方法執(zhí)行線程和發(fā)事件的線程在同一個線程披诗,這樣可能會引起阻塞,必須等一個方法執(zhí)行完后熟空,才能把事件傳遞個下一個方法
2)MAIN 方法在主線程執(zhí)行藤巢,如果發(fā)送事件的線程也在主線程,也可能會造成阻塞息罗,需要等方法執(zhí)行完后掂咒,才會傳遞給下一個方法
3)MAIN_ORDERED 方法在主線程執(zhí)行,不會對發(fā)送事件造成阻塞迈喉,會把監(jiān)聽該事件的方法放到handler的消息隊列中執(zhí)行
4)BACKGROUND 子線程中執(zhí)行绍刮,如果發(fā)送事件的線程不是主線程,則直接會在這個線程中執(zhí)行挨摸,這種情況同樣可能會引起阻塞孩革,必須等一個方法執(zhí)行完后,才能把事件傳遞個下一個方法
5)ASYNC 子線程中執(zhí)行得运,總是保持和發(fā)送事件的線程不在同一個線程膝蜈,會通過線程池進行執(zhí)行方法
三、取消注冊事件
這一步比較簡單熔掺,eventBus里面有一個map集合饱搏,key為對應(yīng)的注冊的對象類,value為list集合置逻,里面保存著和這對象類有關(guān)的所有event事件類型推沸。
1、根據(jù)這個對象找出所有的事件類型券坞,
2鬓催、然后再根據(jù)事件類型從另一個集合中找出事件類型所對應(yīng)的所有方法
3、遍歷這些方法恨锚,移除掉屬于這個對象類的方法
取消注冊事件就算成功了
在注冊時宇驾,會根據(jù)是否用到了注冊索引類來進行注冊,這個是在編譯階段就把對應(yīng)的方法找到了眠冈,可以提高執(zhí)行效率飞苇,以后再進行分析