介紹
? EventBus
是一種用于Android的發(fā)布/訂閱事件總線饿肺。在我們開發(fā)中經(jīng)常將其應用于Activity
之間鳖敷,Fragment
之間的通訊傳值等匿又。它能達到簡化組件間的通信,以及解耦事件的發(fā)送者和接受者的作用塘秦。
EventBus
使用十分簡單讼渊,在需要發(fā)送數(shù)據(jù)的地方調(diào)用post
方法,并將數(shù)據(jù)對象傳入
EventBus.getDefault(this).post("test");
? 在我們期望接受到數(shù)據(jù)的地方尊剔,注冊EventBus
爪幻,并寫一個帶有@Subscribe注解的方法,該方法只有一個參數(shù)须误,并且其數(shù)據(jù)類型與post
方法發(fā)送的數(shù)據(jù)類型一樣挨稿。該方法就會接收到post發(fā)送的數(shù)據(jù)。
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
EventBus.getDefault().register(this);
}
@Subscribe()
public void receiveValue(String msg){
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
源碼分析
基于EventBus3.1.1
? 如上京痢,EventBus
有三個關(guān)鍵節(jié)點奶甘,register
注冊、post
發(fā)送和unregister
取消注冊祭椰。這里就根據(jù)這三個節(jié)點來簡單分析下源碼臭家。
register注冊流程
首先通過getDefault
方法獲取EventBus單例對象
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
下面是register
方法,該方法是注冊給定的用來接收事件的subscriber
訂閱者吭产。
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
? 首先我們看到侣监,調(diào)用了subscriber.getClass()
方法得到了訂閱者的class對象,如上面的例子我們得到的就是Activity的class對象臣淤。這里又將這個class對象傳到findSubscriberMethods
中橄霉,findSubscriberMethods
的作用是找到訂閱者中所有@Subscribe注解標記的方法,將其封裝成SubscriberMethod
對象并將其添加到集合中返回邑蒋。
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
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;
}
}
? 首先會去METHOD_CACHE這個Map中取訂閱者的方法集合姓蜂,如果存在就將其直接返回。如果沒有緩存医吊,再去查找钱慢。ignoreGeneratedIndex
屬性值默認為false,這個變量在初始化SubscriberMethodFinder
對象時傳入
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
所以卿堂,此時執(zhí)行findUsingInfo
方法束莫。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != 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);
}
? 這里先初始化FindState
對象,并調(diào)用其initForSubscriber
方法為FindState
的clazz
屬性賦值為訂閱者的class
對象草描,如下
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
? 那么此時while (findState.clazz != null)
判斷就成立了览绿,再執(zhí)行getSubscriberInfo
方法獲取subscriberInfo
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;
}
? 上面在initForSubscriber
方法中為subscriberInfo
賦值為空,而subscriberInfoIndexes
屬性在實例化SubscriberMethodFinder
對象時通過EventBusBuilder
對象傳入穗慕,其值也為空饿敲。所以這里的if (findState.subscriberInfo != null)
條件不成立,繼續(xù)執(zhí)行else
分支的findUsingReflectionInSingleClass
方法逛绵。
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
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();
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");
}
}
}
? 首先獲取所有聲明在訂閱者類中的方法數(shù)組methods
怀各,然后遍歷methods
數(shù)組倔韭,獲取方法的修飾符modifiers
,判斷語句(modifiers & Modifier.PUBLIC) != 0
通過修飾符和PUBLIC
對應的值進行按位與運算來判斷方法的修飾符是否為PUBLIC
,不等于0即為PUBLIC
;判斷語句(modifiers & MODIFIERS_IGNORE) == 0
瓢对,其中MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;
這個MODIFIERS_IGNORE
的值與modifiers
按位與即判斷修飾符是否是MODIFIERS_IGNORE
中的任意一個寿酌,結(jié)果為0即沒有這些修飾符。所以經(jīng)過這個判斷沥曹,即保證了@Subscribe
注解的方法必須是public
份名,非靜態(tài)以及非抽象的方法。
? 進入到if
分支妓美,通過getParameterTypes
獲取到方法的參數(shù)類型數(shù)組parameterTypes
僵腺,判斷數(shù)組長度為1時繼續(xù)執(zhí)行,否則拋出異常壶栋,也就是這里限制了@Subscribe
方法只能有一個參數(shù)辰如。然后獲取方法上的@Subscribe
注解,通過parameterTypes[0]
獲取到了方法參數(shù)的類型eventType
贵试。if (findState.checkAdd(method, eventType))
這個判斷的checkAdd
方法做了兩層檢查琉兜,即判斷該方法是否已經(jīng)添加到集合中了,返回true即沒有添加過毙玻,繼而獲取到注解上聲明的線程threadMode
豌蟋,并將method
方法名、eventType
參數(shù)類型桑滩、threadMode
線程梧疲、priority
優(yōu)先級、sticky
粘性封裝成SubscriberMethod
對象添加到findState.subscriberMethods
集合中运准。到這里幌氮,subscribe
方法中findSubscriberMethods
查找訂閱方法的流程執(zhí)行結(jié)束,并得到了List
<SubscriberMethod> 格式的集合胁澳。遍歷前面得到的集合并調(diào)用Subscribe
方法
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
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) {
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);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
? 首先將subscriber
訂閱者對象和SubscriberMethod
訂閱方法對象封裝成Subscription
對象该互。在該方法中建立了兩個Map關(guān)聯(lián)關(guān)系
,第一個:以事件類型為key
韭畸,CopyOnWriteArrayList<Subscription>
為value
存到subscriptionsByEventType
這個Map
中宇智,這樣就建立了 eventType
事件類型和CopyOnWriteArrayList<Subscription>
((訂閱者對象以及訂閱者類中的訂閱方法)的對象的集合)。第二個:以訂閱者為key
胰丁,以訂閱者類中所有@Subscribe
方法的參數(shù)類型(即訂閱的事件類型)的集合為value
存到typesBySubscriber
這個Map
中普筹。
? 至此register流程就結(jié)束了,這里主要的操作就是找到訂閱類中注解為@Subscribe
的并且修飾符為public
非靜態(tài)非抽象且只有一個參數(shù)的方法隘马,將其封裝為SubscriberMethod
添加到集合中保存起來。
post發(fā)送流程
post
方法將給定的event
事件發(fā)送到Event bus
/** Posts the given event to the event bus. */
public void post(Object event) {
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;
}
}
}
? 首先獲取PostingThreadState
對象妻顶,這個對象中封裝了發(fā)送相關(guān)的狀態(tài)酸员,如eventQueue
為事件集合蜒车,這里將event
事件添加到這個集合中。判斷isPosting
為false
表示當前未處于發(fā)送狀態(tài)幔嗦,再將當前是否處于主線程賦值給isMainThread
屬性酿愧,判斷當事件集合不為空時,調(diào)用postSingleEvent
方法發(fā)送集合中的第一個事件邀泉。
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));
}
}
}
? eventInheritance
屬性代表EventBus
是否會考慮event
事件的繼承結(jié)構(gòu)嬉挡,當該值為true
時發(fā)送一個事件,注冊了這個事件父類的方法也會收到通知汇恤。不管該值為true
或false
都會調(diào)用到postSingleEventForEventType
方法
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
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;
}
? 通過發(fā)送的事件類型從subscriptionsByEventType
中獲取對應的subscriptions
集合庞钢。遍歷subscriptions
集合,調(diào)用postToSubscription
將事件傳到訂閱者中的訂閱方法中
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);
}
}
? 判斷訂閱方法指定的執(zhí)行線程因谎,回調(diào)到指定線程中執(zhí)行訂閱方法基括,即調(diào)用invokeSubscriber
方法
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);
}
}
? 最后通過反射調(diào)用subscriber
對象中的method
方法,并將event
事件傳遞到方法中财岔,至此post發(fā)送流程就結(jié)束了风皿。通過Post發(fā)送事件的eventType
類型從Register流程中構(gòu)造的subscriptionsByEventType這個Map對象中獲取到對應的訂閱者以及其中訂閱方法的集合,遍歷集合再通過反射來執(zhí)行訂閱者中的訂閱方法匠璧。
unregister取消注冊流程
將訂閱者從所有事件類中取消注冊桐款。
/** 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());
}
}
? 遍歷事件類型集合subscribedTypes
,調(diào)用unsubscribeByEventType
方法夷恍,并從subscribedTypes
移除訂閱者subscriber
魔眨。
/** 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--;
}
}
}
}
? 根據(jù)事件類型獲取到subscriptions
集合,遍歷集合裁厅,并將當前訂閱者subscriber
對應的Subscription
對象從集合中移除冰沙。取消注冊流程比較簡單,從typesBySubscriber
中移除subscriber
执虹,從subscriptions
集合中將subscriber
對應的Subscription
對象移除拓挥。