EventBus地址:https://github.com/greenrobot/EventBus
一、eventbus使用
EventBus是用于在Android和java中 發布/訂閱 的事件總線
使用EventBus三部曲
1、定義事件Event
public static class MessageEvent { /* Additional fields if needed */ }
2、聲明并注解一個訂閱者
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
其中@Subscribe(threadMode = ThreadMode.MAIN)
的threadMode 可以指定此方法運行的線程模式,threadMode = ThreadMode.MAIN
運行在UI線程,即onMessageEvent不能做耗時操作。
注冊和注銷訂閱者,如果你是在做android開發,那么應該在activity/fragment的生命周期中進行注冊/注銷。
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
3、發布事件
EventBus.getDefault().post(new MessageEvent());
二、分析EventBus源碼
1、EventBus的注冊 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并不是一個嚴格意義上的單例模式,因為它的構造方法并不是私有的,所以你可以創建多個EventBus。
不了解單利模式可以看去之前寫的文章《設計模式—單例》
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);
從命名可以看出是對訂閱者方法的查找,并返回訂閱者方法集合。再看下具體實現
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
是個標志位,true的情況下是通過反射來獲取訂閱者方法列表,false下是在編譯期間生成SubscriberInfo,然后在運行時使用SubscriberInfo中保存的事件處理函數事件,減少了反射的耗時,會有運行速度上的提升,默認情況下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();
}
這里使用了緩存來避免對象的頻繁創建所帶來的開銷,同時可以避免內存抖動;注意這里使用synchronized來避免出現兩個或兩個以上線程操作同一個FindState對象。[這個技巧可以用于出來摸個對象的頻繁創建銷毀,及內存抖動激烈的問題]
>> FindState
static class FindState {
// 訂閱者方法集合
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
// event為key,method為value
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
// 用method的名字生成一個method為key,用訂閱者類為value
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
// 跳過父類,默認false-不跳過
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
// 釋放資源,并恢復默認設置
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
......
// 移至父類【給clazz賦值父類】
// 如果clazz是java包和android包里的,賦值null,并結束
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;
}
}
}
}
主要說明已經放到注釋上。
// 將滿足條件的方法及參數類型添加到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.
// 這個涉及到兩層檢查
// 第一層判斷有無method監聽此eventType,如果沒有則可直接把找到的method加到subscriberMethods中。
// 第二層判斷是方法簽名,這里的方法簽名其實是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的父類或者同一個類
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;
}
}
這兩個方法是FindState最重要的兩個方法,這里單獨舉例說明下:
第一種情況:比如一個類有多個訂閱方法,方法名不同,但它們的參數類型都是相同的(雖然一般不這樣寫,但不排除這樣的可能),那么遍歷這些方法的時候,會多次調用到checkAdd方法,由于existing不為null,那么會進而調用checkAddWithMethodSignature方法,但是由于每個方法的名字都不同,因此methodClassOld會一直為null,因此都會返回true。也就是說,允許一個類有多個參數相同的訂閱方法。
第二種情況:類B繼承自類A,而每個類都是有相同訂閱方法,換句話說,類B的訂閱方法繼承并重寫自類A,它們都有著一樣的方法簽名。方法的遍歷會從子類開始,即B類,在checkAddWithMethodSignature方法中,methodClassOld為null,那么B類的訂閱方法會被添加到列表中。接著,向上找到類A的訂閱方法,由于methodClassOld不為null而且顯然類B不是類A的父類,methodClassOld.isAssignableFrom(methodClass)也會返回false,那么會返回false。也就是說,子類繼承并重寫了父類的訂閱方法,那么只會把子類的訂閱方法添加到訂閱者列表,父類的方法會忽略。
>回到private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass)
,來看這個句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】方法,和從基類繼承的、從接口實現的所有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) {
// 獲得一個方法參數數組(getparameterTypes用于返回一個描述參數類型的Class對象數組)
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();
// 不合法的注解方法 (必須為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方法,和從基類繼承的、從接口實現的所有public方法。而使用此方法自然不需要再遍歷父類的方法,所以findState.skipSuperClasses = true;
來跳過父類的遍歷。
③int modifiers = method.getModifiers();
獲取字段的修飾符
對應如下: 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()));
}
}
}
當方法參數個數為1,并且此方法有Subscribe類型的注解時,通過findState.checkAdd(method, eventType)
將方法和參數類型保存起來,如果保存成功,則構造一個SubscriberMethod對象把數據保存,并添加到findState.subscriberMethods集合中。
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;
}
⑤else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class))
strictMethodVerification表示是否進行精細檢查,默認值是false。如果精細檢查【即strictMethodVerification=true】,并且method含有Subscribe對象的注解,則拋出異常
-
subscriberMethods = findUsingInfo(subscriberClass);
總算分析完了findUsingReflection
,我們接著分析findUsingInfo
,先發下源碼
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 獲取訂閱者信息,沒有配置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 {
// 通過反射來查找訂閱方法
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);
這里涉及到一個EventBus的高級用法,也就是通過注解在編譯期動態生成一個MyEventBusIndex.java
類,從而避免通過反射來查找滿足條件的方法。下面給出官方文檔及兩篇這個高級用法的文章:
官方總文檔地址:http://greenrobot.org/eventbus/documentation/
官方地址:https://github.com/greenrobot/EventBus
博客一:EventBus高級使用姿勢
博客二:EventBus3.0新特性之Subscriber Index
如果沒有配置這個高級用法,findState.subscriberInfo
值便會是null
,然后通過反射去獲取方法并篩選。
MyEventBusIndex.java
文件生成位置【我是用的是kotlin方案,不同的方案位置會有小的區別,但大致位置都是在source下】
注意:在匿名類中是用EventBus時,這種高級用法是不會在MyEventBusIndex.java
生成相關信息的(原因請自行百度),但會執行反射的邏輯來完成對方法的篩選。
subscribe(subscriber, subscriberMethod);
再來分析下register(this);
最后一句代碼subscribe(subscriber, subscriberMethod);
,源碼如下
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
// 從訂閱方法中拿到訂閱事件的類型
Class<?> eventType = subscriberMethod.eventType;
// 創建一個新的訂閱
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 通過訂閱事件類型,找到所有的訂閱(Subscription),訂閱中包含了訂閱者,訂閱方法
// CopyOnWriteArrayList是一個ArrayList的線程安全的變體,具體原理,使用請自行百度
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
// 如果該訂閱事件類型 沒有訂閱列表,那么創建一個該事件類型的訂閱列表
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);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {
// eventInheritance=true時(默認為true)
// EventBus會考慮事件的超類,即事件如果繼承自超類,那么該超類也會作為事件發送給訂閱者。
// 比如 A extends B implements C 發布者post(A),那么找訂閱者的時候不僅要找訂閱了事件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);
}
}
}
> 大部分代碼的理解已放到代碼的注釋中了,這里我單獨拉出下面這段代碼分析下
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);
}
}
}
先簡單寫一個列子,方法講解
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 { }
當ClazzA
構造的時候會執行EventBus
的注冊流程,又因為ClazzA
中的訂閱方法eventbusMain
是sticky
所以會執行subscribe(subscriber, subscriberMethod);
方法中的subscriberMethod.sticky
模塊內代碼,而我們的EventBus
是默認構造EventBus.getDefault()
,也就是說eventInheritance
為true
會執行eventInheritance
代碼塊,如果這個時候stickyEvents.entrySet()
中有兩個Event事件對象 【a是EventA類型,b是BaseEvent類型】,通過for
循環后,這兩個對象都會交給eventbusMain(BaseEvent event)
執行,也就是說eventType.isAssignableFrom(candidateEventType)
這兩個對象都會通過,【第一次循環,BaseEvent是不是BaseEvent的父類或本身? 第二次循環,BaseEvent是不是ClazzA的父類或本身?------ 因為Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
是個集合,順序是不確定,可能是反的,不要糾結】
-
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
發送訂閱事件類給訂閱者
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 {
// 執行訂閱方法
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 用法及說明
- PostThread:默認的 ThreadMode,表示在執行 Post 操作的線程直接調用訂閱者的事件響應方法,不論該線程是否為主線程(UI 線程)。當該線程為主線程時,響應方法中不能有耗時操作,否則有卡主線程的風險。適用場景:對于是否在主線程執行無要求,但若 Post 線程為主線程,不能耗時的操作;
- MainThread:在主線程中執行響應方法。如果發布線程就是主線程,則直接調用訂閱者的事件響應方法,否則通過主線程的 Handler 發送消息在主線程中處理——調用訂閱者的事件響應函數。顯然,MainThread類的方法也不能有耗時操作,以避免卡主線程。適用場景:必須在主線程執行的操作;
- BackgroundThread:在后臺線程中執行響應方法。如果發布線程不是主線程,則直接調用訂閱者的事件響應函數,否則啟動唯一的后臺線程去處理。由于后臺線程是唯一的,當事件超過一個的時候,它們會被放在隊列中依次執行,因此該類響應方法雖然沒有PostThread類和MainThread類方法對性能敏感,但最好不要有重度耗時的操作或太頻繁的輕度耗時操作,以造成其他操作等待。適用場景:操作輕微耗時且不會過于頻繁,即一般的耗時操作都可以放在這里;
- Async:不論發布線程是否為主線程,都使用一個空閑線程來處理。和BackgroundThread不同的是,Async類的所有線程是相互獨立的,因此不會出現卡線程的問題。適用場景:長耗時操作,例如網絡訪問。
mainThreadPoster.enqueue(subscription, event);
主線程執行訂閱方法。
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()
其實是通過反射android中的"android.util.Log"
包是否存在來實現的,代碼如下:
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;
}
........
}
.......
}
在靜態代碼塊中做的反射【只會執行一次】,靜態代碼塊的知識偏離本文重點,請自行百度。
Object getAndroidMainLooperOrNull() {
try {
// 獲得android主線程的looper
return Looper.getMainLooper();
} catch (RuntimeException e) {
// Not really a functional Android (e.g. "Stub!" maven dependencies)
return null;
}
}
這個方法是用來獲得android主線程的looper對象。
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) {
// 構造一個post意圖對象
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
// 將構造的PendingPost 加入到隊列中
queue.enqueue(pendingPost);
if (!handlerActive) {
// handler標記為活躍狀態
handlerActive = true;
// 發送PendingPost對象
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) {
// 從隊列中獲得要執行的PendingPost
PendingPost pendingPost = queue.poll();
// 雙重加鎖檢查,如果隊列中沒有信息,則hanlder狀態標記為不活躍狀態,同事退出循環
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
// 執行訂閱者的訂閱方法
eventBus.invokeSubscriber(pendingPost);
// 循環發送隊列中的所有pendingPost對象
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
是通過主線程的Looper
構造一個主線程的handler
對象,這個handler
中維護了一個隊列PendingPostQueue
,也就是說mainThreadPoster.enqueue(subscription, event);
是通過構造PendingPost
對象并添加到隊列中,然后激活隊列來實現發送。
backgroundPoster.enqueue(subscription, event);
后臺線程中執行響應方法
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;
}
}
}
// 創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
主要代碼就一句eventBus.getExecutorService().execute(this);
交給線程池處理。
asyncPoster.enqueue(subscription, event);不論發布線程是否為主線程,都使用一個空閑線程來處理。和BackgroundThread不同的是,Async類的所有線程是相互獨立的,因此不會出現卡線程的問題。
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
代碼基本一樣,這里就不分析。它們兩個主要區別就是BackgroundPoster
把一堆訂閱方法放在一個線程中執行,而AsyncPoster
是為每一個訂閱方法都創建一個線程來單獨執行。
-
總結:到這終于分析完了EventBus的
register()
的整個流程。下面我繪制了一個流程圖來方便理解整個注冊流程。
EventBus整個register流程
2、EventBus的訂閱方法聲明
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
2-1、訂閱方法說明
在上面的EventBus.getDefault()
流程分支中,我們得知EventBus
的訂閱方法必須是public
,一個參數,并且要一定要有@Subscribe
的注解,才能成功的將該方法添加到EventBus的訂閱方法列表中,同時EventBus提供了兩種方法來查找我們的訂閱方法,一種是反射【效率低】,另一種是通過注解,在編譯期動態生成訂閱者方法列表【效率高】。
2-2、Subscribe都有哪些注解參數
@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;
}
源碼中看出就三個屬性參數,分別是線程模式、是否粘性、優先級。
3、EventBus發布事件EventBus.getDefault().post(new MessageEvent());
3-1、void post(Object event)
public void post(Object event) {
// 獲得當前線程的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
中獲取PostingThreadState
對象,來下看currentPostingThreadState
的定義
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
看來currentPostingThreadState
是一個ThreadLocal<T>
對象,ThreadLocal
是一個線程內部的數據存儲類,通過它可以在指定的線程中存儲數據,而這段數據是不會與其他線程共享的。【下面是一段跑題代碼】
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();
}
}
// 其內部原理是通過生成一個它包裹的泛型對象的數組,在不同的線程會有不同的數組索引值,
// 通過這樣就可以做到每個線程通過 get() 方法獲取的時候,取到的只能是自己線程所對應的數據。
回到正題繼續分析
/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>(); // 事件隊列
boolean isPosting; // 是否在執行postSingleEvent()方法
boolean isMainThread; // 是否是UI線程
Subscription subscription;
Object event;
boolean canceled;
}
PostingThreadState
主要是封裝了一些post時的參數。
post(Object event)的核心代碼就是這個句,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);
// 有一個為true,即真個運算結果為true
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);
}
// sendNoSubscriberEvent=true發送沒有此事件類型的訂閱者的事件
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
是用來獲取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一個map的緩存對象,通過緩存,提高運行效率
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());
}
}
}
這里通過遞歸來查找出所有的接口,并添加到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 {
// 調用所有訂閱了此類型的,訂閱方法
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()
中已有相關分析,這里不贅述了;
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
中,然后調用void post(Object event)
,就和上面的分析一樣了,這里把event
添加到stickyEvents
目的是,當后續有register(this);
時執行sticky訂閱方法。
4、EventBus的反注冊 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就是進行一些數據從集合中移除,資源回收的操作和重置,看看就可以了。
PS:終于算分析完了,一貫只看不寫我的,第一次寫這么長的源碼分析文章,寫到最后自己都想放棄,但抱著做事要有始有終,還是堅持寫完了@@@@@@~~~~~!!!!