EventBus地址:https://github.com/greenrobot/EventBus
一谤狡、eventbus使用
EventBus是用于在Android和java中 發(fā)布/訂閱 的事件總線
使用EventBus三部曲
1喳资、定義事件Event
public static class MessageEvent { /* Additional fields if needed */ }
2糕珊、聲明并注解一個(gè)訂閱者
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
其中@Subscribe(threadMode = ThreadMode.MAIN)
的threadMode 可以指定此方法運(yùn)行的線程模式贮折,threadMode = ThreadMode.MAIN
運(yùn)行在UI線程,即onMessageEvent不能做耗時(shí)操作导街。
注冊(cè)和注銷訂閱者耻蛇,如果你是在做android開發(fā),那么應(yīng)該在activity/fragment的生命周期中進(jìn)行注冊(cè)/注銷朝蜘。
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
3恶迈、發(fā)布事件
EventBus.getDefault().post(new MessageEvent());
二、分析EventBus源碼
1谱醇、EventBus的注冊(cè) EventBus.getDefault().register(this);
1-1暇仲、EventBus.getDefault()
源碼
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
從源碼看,EventBus的getDefault()是采用的是單例模式枣抱,并且是線程安全熔吗,注意EventBus并不是一個(gè)嚴(yán)格意義上的單例模式,因?yàn)樗臉?gòu)造方法并不是私有的佳晶,所以你可以創(chuàng)建多個(gè)EventBus桅狠。
不了解單利模式可以看去之前寫的文章《設(shè)計(jì)模式—單例》
1-2、register(this);
源碼
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
先看這句List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
從命名可以看出是對(duì)訂閱者方法的查找轿秧,并返回訂閱者方法集合中跌。再看下具體實(shí)現(xiàn)
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// 先從緩存中取出subscriberMethods,如果有則直接返回METHOD_CACHE的value
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
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;
}
}
-
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
檢查Map中是否緩存了此訂閱者的方法集合菇篡,有直接返回漩符; -
ignoreGeneratedIndex
是個(gè)標(biāo)志位,true的情況下是通過(guò)反射來(lái)獲取訂閱者方法列表驱还,false下是在編譯期間生成SubscriberInfo嗜暴,然后在運(yùn)行時(shí)使用SubscriberInfo中保存的事件處理函數(shù)事件凸克,減少了反射的耗時(shí),會(huì)有運(yùn)行速度上的提升闷沥,默認(rèn)情況下ignoreGeneratedIndex值是false的 -
subscriberMethods = findUsingReflection(subscriberClass);
看下源碼
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass(); // 移至父類
}
return getMethodsAndRelease(findState);
}
> FindState findState = prepareFindState();
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
這里使用了緩存來(lái)避免對(duì)象的頻繁創(chuàng)建所帶來(lái)的開銷萎战,同時(shí)可以避免內(nèi)存抖動(dòng);注意這里使用synchronized來(lái)避免出現(xiàn)兩個(gè)或兩個(gè)以上線程操作同一個(gè)FindState對(duì)象舆逃。[這個(gè)技巧可以用于出來(lái)摸個(gè)對(duì)象的頻繁創(chuàng)建銷毀蚂维,及內(nèi)存抖動(dòng)激烈的問(wèn)題]
>> FindState
static class FindState {
// 訂閱者方法集合
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
// event為key,method為value
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
// 用method的名字生成一個(gè)method為key路狮,用訂閱者類為value
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
// 跳過(guò)父類虫啥,默認(rèn)false-不跳過(guò)
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
// 釋放資源,并恢復(fù)默認(rèn)設(shè)置
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
......
// 移至父類【給clazz賦值父類】
// 如果clazz是java包和android包里的奄妨,賦值null涂籽,并結(jié)束
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
}
主要說(shuō)明已經(jīng)放到注釋上。
// 將滿足條件的方法及參數(shù)類型添加到anyMethodByEventType中
boolean checkAdd(Method method, Class<?> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
// 這個(gè)涉及到兩層檢查
// 第一層判斷有無(wú)method監(jiān)聽此eventType,如果沒(méi)有則可直接把找到的method加到subscriberMethods中展蒂。
// 第二層判斷是方法簽名又活,這里的方法簽名其實(shí)是methodName+eventType
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
// 方法簽名
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
// 拼接所謂的方法簽名
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class<?> methodClass = method.getDeclaringClass(); // 獲得聲明此method的類
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
// “methodClassOld.isAssignableFrom(methodClass)” methodClassOld是否是methodClass的父類或者同一個(gè)類
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
return true;
} else {
// Revert the put, old class is further down the class hierarchy
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
這兩個(gè)方法是FindState最重要的兩個(gè)方法,這里單獨(dú)舉例說(shuō)明下:
第一種情況:比如一個(gè)類有多個(gè)訂閱方法锰悼,方法名不同柳骄,但它們的參數(shù)類型都是相同的(雖然一般不這樣寫,但不排除這樣的可能)箕般,那么遍歷這些方法的時(shí)候耐薯,會(huì)多次調(diào)用到checkAdd方法,由于existing不為null丝里,那么會(huì)進(jìn)而調(diào)用checkAddWithMethodSignature方法曲初,但是由于每個(gè)方法的名字都不同,因此methodClassOld會(huì)一直為null杯聚,因此都會(huì)返回true臼婆。也就是說(shuō),允許一個(gè)類有多個(gè)參數(shù)相同的訂閱方法幌绍。
第二種情況:類B繼承自類A颁褂,而每個(gè)類都是有相同訂閱方法,換句話說(shuō)傀广,類B的訂閱方法繼承并重寫自類A颁独,它們都有著一樣的方法簽名。方法的遍歷會(huì)從子類開始伪冰,即B類誓酒,在checkAddWithMethodSignature方法中,methodClassOld為null贮聂,那么B類的訂閱方法會(huì)被添加到列表中靠柑。接著寨辩,向上找到類A的訂閱方法,由于methodClassOld不為null而且顯然類B不是類A的父類歼冰,methodClassOld.isAssignableFrom(methodClass)也會(huì)返回false捣染,那么會(huì)返回false。也就是說(shuō)停巷,子類繼承并重寫了父類的訂閱方法,那么只會(huì)把子類的訂閱方法添加到訂閱者列表榕栏,父類的方法會(huì)忽略畔勤。
>回到private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass)
,來(lái)看這個(gè)句findUsingReflectionInSingleClass(findState);
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
// 獲取的是類【自身】聲明的所有方法扒磁,包含public庆揪、protected和private方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
// 獲取的是類的所有共有方法,**這就包括自身的所有【public】方法妨托,和從基類繼承的缸榛、從接口實(shí)現(xiàn)的所有public方法**
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers(); // 獲取字段的修飾符
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 獲得一個(gè)方法參數(shù)數(shù)組(getparameterTypes用于返回一個(gè)描述參數(shù)類型的Class對(duì)象數(shù)組)
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();
// 不合法的注解方法 (方法只能有一個(gè)參數(shù))
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();
// 不合法的注解方法 (必須為public,非static兰伤、非abstract)
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
①getDeclaredMethods()
獲取的是類自身聲明的所有方法内颗,包含public、protected和private方法敦腔。
②getMethods()
獲取的是類的所有共有方法均澳,這就包括自身的所有public方法,和從基類繼承的符衔、從接口實(shí)現(xiàn)的所有public方法找前。而使用此方法自然不需要再遍歷父類的方法,所以findState.skipSuperClasses = true;
來(lái)跳過(guò)父類的遍歷判族。
③int modifiers = method.getModifiers();
獲取字段的修飾符
對(duì)應(yīng)如下: PUBLIC: 1 PRIVATE: 2 PROTECTED: 4 STATIC: 8 FINAL: 16 SYNCHRONIZED: 32 VOLATILE: 64 TRANSIENT: 128 NATIVE: 256 INTERFACE: 512 ABSTRACT: 1024 STRICT: 2048
④if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0)
private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;
只獲取public類型的方法
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()));
}
}
}
當(dāng)方法參數(shù)個(gè)數(shù)為1躺盛,并且此方法有Subscribe類型的注解時(shí),通過(guò)findState.checkAdd(method, eventType)
將方法和參數(shù)類型保存起來(lái)形帮,如果保存成功槽惫,則構(gòu)造一個(gè)SubscriberMethod對(duì)象把數(shù)據(jù)保存,并添加到findState.subscriberMethods集合中沃缘。
public class SubscriberMethod {
final Method method; // 方法
final ThreadMode threadMode; // 方法運(yùn)行線程類型
final Class<?> eventType; // 參數(shù)類型
final int priority; // 優(yōu)先級(jí)
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;
}
⑤else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class))
strictMethodVerification表示是否進(jìn)行精細(xì)檢查躯枢,默認(rèn)值是false。如果精細(xì)檢查【即strictMethodVerification=true】槐臀,并且method含有Subscribe對(duì)象的注解锄蹂,則拋出異常
-
subscriberMethods = findUsingInfo(subscriberClass);
總算分析完了findUsingReflection
,我們接著分析findUsingInfo
水慨,先發(fā)下源碼
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 獲取訂閱者信息得糜,沒(méi)有配置MyEventBusIndex返回null
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
// 通過(guò)反射來(lái)查找訂閱方法
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
private SubscriberInfo getSubscriberInfo(FindState findState) {
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
> findState.subscriberInfo = getSubscriberInfo(findState);
這里涉及到一個(gè)EventBus的高級(jí)用法敬扛,也就是通過(guò)注解在編譯期動(dòng)態(tài)生成一個(gè)MyEventBusIndex.java
類,從而避免通過(guò)反射來(lái)查找滿足條件的方法朝抖。下面給出官方文檔及兩篇這個(gè)高級(jí)用法的文章:
官方總文檔地址:http://greenrobot.org/eventbus/documentation/
官方地址:https://github.com/greenrobot/EventBus
博客一:EventBus高級(jí)使用姿勢(shì)
博客二:EventBus3.0新特性之Subscriber Index
如果沒(méi)有配置這個(gè)高級(jí)用法啥箭,findState.subscriberInfo
值便會(huì)是null
,然后通過(guò)反射去獲取方法并篩選治宣。
MyEventBusIndex.java
文件生成位置【我是用的是kotlin方案急侥,不同的方案位置會(huì)有小的區(qū)別,但大致位置都是在source下】
注意:在匿名類中是用EventBus時(shí)侮邀,這種高級(jí)用法是不會(huì)在MyEventBusIndex.java
生成相關(guān)信息的(原因請(qǐng)自行百度)坏怪,但會(huì)執(zhí)行反射的邏輯來(lái)完成對(duì)方法的篩選。
subscribe(subscriber, subscriberMethod);
再來(lái)分析下register(this);
最后一句代碼subscribe(subscriber, subscriberMethod);
绊茧,源碼如下
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
// 從訂閱方法中拿到訂閱事件的類型
Class<?> eventType = subscriberMethod.eventType;
// 創(chuàng)建一個(gè)新的訂閱
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 通過(guò)訂閱事件類型铝宵,找到所有的訂閱(Subscription),訂閱中包含了訂閱者,訂閱方法
// CopyOnWriteArrayList是一個(gè)ArrayList的線程安全的變體华畏,具體原理鹏秋,使用請(qǐng)自行百度
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
// 如果該訂閱事件類型 沒(méi)有訂閱列表,那么創(chuàng)建一個(gè)該事件類型的訂閱列表
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();
// 根據(jù)訂閱方法的優(yōu)先級(jí)亡笑,添加到訂閱列表
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
// 將這個(gè)訂閱事件加入到訂閱者的訂閱事件列表中
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {
// eventInheritance=true時(shí)(默認(rèn)為true)
// EventBus會(huì)考慮事件的超類侣夷,即事件如果繼承自超類,那么該超類也會(huì)作為事件發(fā)送給訂閱者仑乌。
// 比如 A extends B implements C 發(fā)布者post(A),那么找訂閱者的時(shí)候不僅要找訂閱了事件A的訂閱者惜纸,還要找訂閱了B和C的訂閱者
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>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
// eventType是否是candidateEventType的父類或本身
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
> 大部分代碼的理解已放到代碼的注釋中了,這里我單獨(dú)拉出下面這段代碼分析下
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>).
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);
}
}
}
先簡(jiǎn)單寫一個(gè)列子绝骚,方法講解
public class ClazzA {
public ClazzA() { EventBus.getDefault().register(this); }
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void eventbusMain(BaseEvent event) { }
}
public class BaseEvent { }
public class EventA extends BaseEvent { }
當(dāng)ClazzA
構(gòu)造的時(shí)候會(huì)執(zhí)行EventBus
的注冊(cè)流程耐版,又因?yàn)?code>ClazzA中的訂閱方法eventbusMain
是sticky
所以會(huì)執(zhí)行subscribe(subscriber, subscriberMethod);
方法中的subscriberMethod.sticky
模塊內(nèi)代碼,而我們的EventBus
是默認(rèn)構(gòu)造EventBus.getDefault()
,也就是說(shuō)eventInheritance
為true
會(huì)執(zhí)行eventInheritance
代碼塊压汪,如果這個(gè)時(shí)候stickyEvents.entrySet()
中有兩個(gè)Event事件對(duì)象 【a是EventA類型粪牲,b是BaseEvent類型】,通過(guò)for
循環(huán)后止剖,這兩個(gè)對(duì)象都會(huì)交給eventbusMain(BaseEvent event)
執(zhí)行腺阳,也就是說(shuō)eventType.isAssignableFrom(candidateEventType)
這兩個(gè)對(duì)象都會(huì)通過(guò),【第一次循環(huán)穿香,BaseEvent是不是BaseEvent的父類或本身亭引? 第二次循環(huán),BaseEvent是不是ClazzA的父類或本身皮获?------ 因?yàn)?code>Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();是個(gè)集合焙蚓,順序是不確定,可能是反的,不要糾結(jié)】
-
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
發(fā)送訂閱事件類給訂閱者
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.
postToSubscription(newSubscription, stickyEvent, 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);
}
}
void invokeSubscriber(Subscription subscription, Object event) {
try {
// 執(zhí)行訂閱方法
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
ThreadMode 用法及說(shuō)明
- PostThread:默認(rèn)的 ThreadMode购公,表示在執(zhí)行 Post 操作的線程直接調(diào)用訂閱者的事件響應(yīng)方法萌京,不論該線程是否為主線程(UI 線程)。當(dāng)該線程為主線程時(shí)宏浩,響應(yīng)方法中不能有耗時(shí)操作知残,否則有卡主線程的風(fēng)險(xiǎn)。適用場(chǎng)景:對(duì)于是否在主線程執(zhí)行無(wú)要求比庄,但若 Post 線程為主線程求妹,不能耗時(shí)的操作;
- MainThread:在主線程中執(zhí)行響應(yīng)方法佳窑。如果發(fā)布線程就是主線程扒最,則直接調(diào)用訂閱者的事件響應(yīng)方法,否則通過(guò)主線程的 Handler 發(fā)送消息在主線程中處理——調(diào)用訂閱者的事件響應(yīng)函數(shù)华嘹。顯然,MainThread類的方法也不能有耗時(shí)操作法竞,以避免卡主線程耙厚。適用場(chǎng)景:必須在主線程執(zhí)行的操作;
- BackgroundThread:在后臺(tái)線程中執(zhí)行響應(yīng)方法岔霸。如果發(fā)布線程不是主線程薛躬,則直接調(diào)用訂閱者的事件響應(yīng)函數(shù),否則啟動(dòng)唯一的后臺(tái)線程去處理呆细。由于后臺(tái)線程是唯一的型宝,當(dāng)事件超過(guò)一個(gè)的時(shí)候,它們會(huì)被放在隊(duì)列中依次執(zhí)行絮爷,因此該類響應(yīng)方法雖然沒(méi)有PostThread類和MainThread類方法對(duì)性能敏感趴酣,但最好不要有重度耗時(shí)的操作或太頻繁的輕度耗時(shí)操作,以造成其他操作等待坑夯。適用場(chǎng)景:操作輕微耗時(shí)且不會(huì)過(guò)于頻繁岖寞,即一般的耗時(shí)操作都可以放在這里;
- Async:不論發(fā)布線程是否為主線程柜蜈,都使用一個(gè)空閑線程來(lái)處理仗谆。和BackgroundThread不同的是,Async類的所有線程是相互獨(dú)立的淑履,因此不會(huì)出現(xiàn)卡線程的問(wèn)題隶垮。適用場(chǎng)景:長(zhǎng)耗時(shí)操作,例如網(wǎng)絡(luò)訪問(wèn)秘噪。
mainThreadPoster.enqueue(subscription, event);
主線程執(zhí)行訂閱方法狸吞。
private final Poster mainThreadPoster;
EventBus(EventBusBuilder builder) {
......
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
......
}
MainThreadSupport getMainThreadSupport() {
if (mainThreadSupport != null) {
return mainThreadSupport;
} else if (Logger.AndroidLogger.isAndroidLogAvailable()) {
// android的Ui線程
Object looperOrNull = getAndroidMainLooperOrNull();
return looperOrNull == null ? null :
new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
} else {
return null;
}
}
其中Logger.AndroidLogger.isAndroidLogAvailable()
其實(shí)是通過(guò)反射android中的"android.util.Log"
包是否存在來(lái)實(shí)現(xiàn)的,代碼如下:
public interface Logger {
........
public static class AndroidLogger implements Logger {
static final boolean ANDROID_LOG_AVAILABLE;
static {
boolean android = false;
try {
android = Class.forName("android.util.Log") != null;
} catch (ClassNotFoundException e) {
// OK
}
ANDROID_LOG_AVAILABLE = android;
}
public static boolean isAndroidLogAvailable() {
return ANDROID_LOG_AVAILABLE;
}
........
}
.......
}
在靜態(tài)代碼塊中做的反射【只會(huì)執(zhí)行一次】,靜態(tài)代碼塊的知識(shí)偏離本文重點(diǎn)捷绒,請(qǐng)自行百度瑰排。
Object getAndroidMainLooperOrNull() {
try {
// 獲得android主線程的looper
return Looper.getMainLooper();
} catch (RuntimeException e) {
// Not really a functional Android (e.g. "Stub!" maven dependencies)
return null;
}
}
這個(gè)方法是用來(lái)獲得android主線程的looper對(duì)象。
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);
}
}
}
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) {
// 構(gòu)造一個(gè)post意圖對(duì)象
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
// 將構(gòu)造的PendingPost 加入到隊(duì)列中
queue.enqueue(pendingPost);
if (!handlerActive) {
// handler標(biāo)記為活躍狀態(tài)
handlerActive = true;
// 發(fā)送PendingPost對(duì)象
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
// 從隊(duì)列中獲得要執(zhí)行的PendingPost
PendingPost pendingPost = queue.poll();
// 雙重加鎖檢查暖侨,如果隊(duì)列中沒(méi)有信息椭住,則hanlder狀態(tài)標(biāo)記為不活躍狀態(tài),同事退出循環(huán)
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
// 執(zhí)行訂閱者的訂閱方法
eventBus.invokeSubscriber(pendingPost);
// 循環(huán)發(fā)送隊(duì)列中的所有pendingPost對(duì)象
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;
}
}
}
可以看出MainThreadSupport
是通過(guò)主線程的Looper
構(gòu)造一個(gè)主線程的handler
對(duì)象字逗,這個(gè)handler
中維護(hù)了一個(gè)隊(duì)列PendingPostQueue
京郑,也就是說(shuō)mainThreadPoster.enqueue(subscription, event);
是通過(guò)構(gòu)造PendingPost
對(duì)象并添加到隊(duì)列中,然后激活隊(duì)列來(lái)實(shí)現(xiàn)發(fā)送葫掉。
backgroundPoster.enqueue(subscription, event);
后臺(tái)線程中執(zhí)行響應(yīng)方法
final class BackgroundPoster implements Runnable, Poster {
private final PendingPostQueue queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
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) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
// 創(chuàng)建一個(gè)可緩存線程池些举,如果線程池長(zhǎng)度超過(guò)處理需要,可靈活回收空閑線程俭厚,若無(wú)可回收户魏,則新建線程。
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
主要代碼就一句eventBus.getExecutorService().execute(this);
交給線程池處理挪挤。
asyncPoster.enqueue(subscription, event);不論發(fā)布線程是否為主線程叼丑,都使用一個(gè)空閑線程來(lái)處理。和BackgroundThread不同的是扛门,Async類的所有線程是相互獨(dú)立的鸠信,因此不會(huì)出現(xiàn)卡線程的問(wèn)題。
class AsyncPoster implements Runnable, Poster {
private final PendingPostQueue queue;
private final EventBus eventBus;
AsyncPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
}
AsyncPoster
和BackgroundPoster
代碼基本一樣论寨,這里就不分析星立。它們兩個(gè)主要區(qū)別就是BackgroundPoster
把一堆訂閱方法放在一個(gè)線程中執(zhí)行,而AsyncPoster
是為每一個(gè)訂閱方法都創(chuàng)建一個(gè)線程來(lái)單獨(dú)執(zhí)行葬凳。
-
總結(jié):到這終于分析完了EventBus的
register()
的整個(gè)流程绰垂。下面我繪制了一個(gè)流程圖來(lái)方便理解整個(gè)注冊(cè)流程。
EventBus整個(gè)register流程
2火焰、EventBus的訂閱方法聲明
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
2-1辕坝、訂閱方法說(shuō)明
在上面的EventBus.getDefault()
流程分支中,我們得知EventBus
的訂閱方法必須是public
荐健,一個(gè)參數(shù)酱畅,并且要一定要有@Subscribe
的注解,才能成功的將該方法添加到EventBus的訂閱方法列表中江场,同時(shí)EventBus提供了兩種方法來(lái)查找我們的訂閱方法纺酸,一種是反射【效率低】,另一種是通過(guò)注解址否,在編譯期動(dòng)態(tài)生成訂閱者方法列表【效率高】餐蔬。
2-2碎紊、Subscribe都有哪些注解參數(shù)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
/**
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
*/
boolean sticky() default false;
/** Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s! */
int priority() default 0;
}
源碼中看出就三個(gè)屬性參數(shù),分別是線程模式樊诺、是否粘性仗考、優(yōu)先級(jí)。
3词爬、EventBus發(fā)布事件EventBus.getDefault().post(new MessageEvent());
3-1秃嗜、void post(Object event)
public void post(Object event) {
// 獲得當(dāng)前線程的PostingThreadState封裝對(duì)象
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) { // 為發(fā)送狀態(tài)
postingState.isMainThread = isMainThread(); // 是否主線程
postingState.isPosting = true; // 設(shè)置為正在發(fā)送狀態(tài)
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState); // 發(fā)送事件
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
第一行源碼是從currentPostingThreadState
中獲取PostingThreadState
對(duì)象,來(lái)下看currentPostingThreadState
的定義
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
看來(lái)currentPostingThreadState
是一個(gè)ThreadLocal<T>
對(duì)象顿膨,ThreadLocal
是一個(gè)線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類锅锨,通過(guò)它可以在指定的線程中存儲(chǔ)數(shù)據(jù),而這段數(shù)據(jù)是不會(huì)與其他線程共享的恋沃”馗悖【下面是一段跑題代碼】
public class ThreadLocal<T> {
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
}
// 其內(nèi)部原理是通過(guò)生成一個(gè)它包裹的泛型對(duì)象的數(shù)組,在不同的線程會(huì)有不同的數(shù)組索引值囊咏,
// 通過(guò)這樣就可以做到每個(gè)線程通過(guò) get() 方法獲取的時(shí)候恕洲,取到的只能是自己線程所對(duì)應(yīng)的數(shù)據(jù)。
回到正題繼續(xù)分析
/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>(); // 事件隊(duì)列
boolean isPosting; // 是否在執(zhí)行postSingleEvent()方法
boolean isMainThread; // 是否是UI線程
Subscription subscription;
Object event;
boolean canceled;
}
PostingThreadState
主要是封裝了一些post時(shí)的參數(shù)梅割。
post(Object event)的核心代碼就是這個(gè)句霜第,postSingleEvent(eventQueue.remove(0), postingState);
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
// 獲取到eventClass所有父類的集合
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
// 有一個(gè)為true,即真?zhèn)€運(yùn)算結(jié)果為true
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
// 沒(méi)有找到此事件類型的訂閱者邏輯
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
// sendNoSubscriberEvent=true發(fā)送沒(méi)有此事件類型的訂閱者的事件
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
是用來(lái)獲取eventClass所繼承的父類炮捧,及所有接口。
/** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
synchronized (eventTypesCache) {
// eventTypesCache一個(gè)map的緩存對(duì)象惦银,通過(guò)緩存咆课,提高運(yùn)行效率
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();
}
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}
/** Recurses through super interfaces. */
// 遞歸方式查找出所有接口
static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
for (Class<?> interfaceClass : interfaces) {
if (!eventTypes.contains(interfaceClass)) {
eventTypes.add(interfaceClass);
addInterfaces(eventTypes, interfaceClass.getInterfaces());
}
}
}
這里通過(guò)遞歸來(lái)查找出所有的接口,并添加到eventTypes
中扯俱;
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// 所有訂閱了eventClass的事件集合
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
// 調(diào)用所有訂閱了此類型的书蚪,訂閱方法
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;
}
postToSubscription(subscription, event, postingState.isMainThread);
上面register()
中已有相關(guān)分析,這里不贅述了迅栅;
3-2殊校、void postSticky(Object event)
private final Map<Class<?>, Object> stickyEvents;
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);
}
如果是粘性事件,將此事件添加到stickyEvents
中读存,然后調(diào)用void post(Object event)
为流,就和上面的分析一樣了,這里把event
添加到stickyEvents
目的是让簿,當(dāng)后續(xù)有register(this);
時(shí)執(zhí)行sticky訂閱方法敬察。
4、EventBus的反注冊(cè) EventBus.getDefault().unregister(this);
1-1尔当、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. */
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--;
}
}
}
}
unregister就是進(jìn)行一些數(shù)據(jù)從集合中移除莲祸,資源回收的操作和重置,看看就可以了。
PS:終于算分析完了锐帜,一貫只看不寫我的田盈,第一次寫這么長(zhǎng)的源碼分析文章,寫到最后自己都想放棄缴阎,但抱著做事要有始有終允瞧,還是堅(jiān)持寫完了@@@@@@~~~~~!R摺4墒健!