EventBus官方介紹為一個為Android系統(tǒng)優(yōu)化的事件訂閱總線奸忽,它不僅可以很方便的在同線程中傳遞事件或者對象,還可以在不同線程中實現(xiàn)事件或?qū)ο蟮膫鬟f纺弊,用法比較簡單筛璧,可以很好地完成一些在原生系統(tǒng)中的Intent逸绎,Handler等可以完成的工作,在Android開發(fā)過程中用途及其廣泛夭谤。當(dāng)然這里不介紹它的具體用法桶良,只走源碼,然后自己動手寫一下加深映象沮翔。很多人都說用了觀察者設(shè)計模式,如果非得要往上靠曲秉,只能說不是正常的觀察者采蚀。當(dāng)然我們也不用太關(guān)注,你就認(rèn)為它是反射加注解承二。如果你會 RXjava 也可以用 RxBus榆鼠,或者自己用 RxJava 簡單的封裝一下也行。
我給別人寫的好幾個項目都用了這個開源庫亥鸠,的確比較方便妆够,可以減少很多不必要的代碼识啦,但是也有某一些問題,就是可讀性并不是特別高神妹,跨度有時還是比較大颓哮,當(dāng)然我們可以采用規(guī)范來避免掉這些問題。
分析源碼其實有很多動機(jī)鸵荠,比如:1. 開發(fā)中出現(xiàn)了一下問題冕茅,報錯或者收不到事件;2. 想了解一下原理蛹找,想知道是怎么個流程姨伤;3. 針對性的學(xué)習(xí),想吸取里面的營養(yǎng)庸疾,想仔細(xì)的學(xué)習(xí)思想乍楚。等等...... 我們也能從 EventBus 里面學(xué)習(xí)到一些有用的知識:
1. 之前學(xué)到的一些設(shè)計模式:享元設(shè)計模式,單例設(shè)計模式届慈,模板設(shè)計模式......
2. 之前學(xué)到的一些基礎(chǔ)知識:volatile 關(guān)鍵字徒溪,線程間的通信安全,線程池的運(yùn)用......
3. 反射和注解的一些細(xì)節(jié)拧篮,反射的緩存词渤,方法的修飾符,方法參數(shù)的反射......
4. 能夠參考 EventBus 源碼自己寫一些項目庫串绩,像跨模塊通信框架缺虐,當(dāng)然大公司像阿里這些都有開源的框架,還用自己寫嗎礁凡?其實有時實現(xiàn)方式根本不一樣高氮,用他們的未必適合自己的運(yùn)行時架構(gòu),其次有時實在是閑著沒事干顷牌。
1.EventBus.register()
public void register(Object subscriber) {
// 首先獲得class對象
Class<?> subscriberClass = subscriber.getClass();
// 通過 subscriberMethodFinder 來找到訂閱者訂閱了哪些事件.返回一個 SubscriberMethod 對象的 List, SubscriberMethod
// 里包含了這個方法的 Method 對象,以及將來響應(yīng)訂閱是在哪個線程的 ThreadMode ,以及訂閱的事件類型 eventType ,以及訂閱的優(yōu)
// 先級 priority ,以及是否接收粘性 sticky 事件的 boolean 值剪芍,其實就是解析這個類上的所有 Subscriber 注解方法屬性。
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// 訂閱
subscribe(subscriber, subscriberMethod);
}
}
}
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// 先從緩存里面讀取窟蓝,訂閱者的 Class
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
// ignoreGeneratedIndex屬性表示是否忽略注解器生成的MyEventBusIndex罪裹。
// ignoreGeneratedIndex的默認(rèn)值為false,可以通過EventBusBuilder來設(shè)置它的值
if (ignoreGeneratedIndex) {
// 利用反射來獲取訂閱類中所有訂閱方法信息
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// 從注解器生成的MyEventBusIndex類中獲得訂閱類的訂閱方法信息
// 這個這里不說运挫,可以去看看之前的編譯時注解
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;
}
}
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 尋找某個類中的所有事件響應(yīng)方法
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass(); //繼續(xù)尋找當(dāng)前類父類中注冊的事件響應(yīng)方法
}
return getMethodsAndRelease(findState);
}
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 循環(huán)所有方法
for (Method method : methods) {
// 獲取方法訪問修飾符
int modifiers = method.getModifiers();
// 找到所有聲明為 public 的方法
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();// 獲取參數(shù)的的 Class
if (parameterTypes.length == 1) {// 只允許包含一個參數(shù)
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
// 獲取事件的 Class 状共,也就是方法參數(shù)的 Class
Class<?> eventType = parameterTypes[0];
// 檢測添加
if (findState.checkAdd(method, eventType)) {
// 獲取 ThreadMode
ThreadMode threadMode = subscribeAnnotation.threadMode();
// 往集合里面添加 SubscriberMethod ,解析方法注解所有的屬性
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");
}
}
}
先看下 findSubscriberMethods() 這個方法谁帕,會通過類對象的 class 去解析這個類中的所有 Subscribe 注解方法的所有屬性值峡继,一個注解方法對應(yīng)一個 SubscriberMethod 對象,包括 threadMode匈挖,priority碾牌,sticky康愤,eventType,methodString舶吗。該方法執(zhí)行完畢之后應(yīng)該是下面這張圖征冷,效果就將就一下吧:
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
// 獲取方法參數(shù)的 class
Class<?> eventType = subscriberMethod.eventType;
// 創(chuàng)建一個 Subscription
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 獲取訂閱了此事件類的所有訂閱者信息列表
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
// 線程安全的 ArrayList
subscriptions = new CopyOnWriteArrayList<>();
// 添加
subscriptionsByEventType.put(eventType, subscriptions);
} else {
// 是否包含,如果包含再次添加拋異常
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
// 處理優(yōu)先級
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;
}
}
// 通過 subscriber 獲取 List<Class<?>>
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);
}
}
}
接下來看下 subscribe 這個方法裤翩,這個相對來說就簡單許多了资盅,把 subscriber , SubscriberMethod 分別存好,到底怎么存踊赠,這個時候看下面這兩個集合:
// subscriptionsByEventType 這個集合存放的是呵扛?
// key 是 Event 參數(shù)的類
// value 存放的是 Subscription 的集合列表
// Subscription 包含兩個屬性,一個是 subscriber 訂閱者(反射執(zhí)行對象)筐带,一個是 SubscriberMethod 注解方法的所有屬性參數(shù)值
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
// typesBySubscriber 這個集合存放的是今穿?
// key 是所有的訂閱者
// value 是所有訂閱者里面方法的參數(shù)的 class,eventType
private final Map<Object, List<Class<?>>> typesBySubscriber;
2.EventBus.post()
/** Posts the given event to the event bus. */
public void post(Object event) {
// currentPostingThreadState 是一個 ThreadLocal伦籍,
// 他的特點是獲取當(dāng)前線程一份獨有的變量數(shù)據(jù)蓝晒,不受其他線程影響。
// 這個在 Handler 里面有過源碼分析
PostingThreadState postingState = currentPostingThreadState.get();
// postingState 就是獲取到的線程獨有的變量數(shù)據(jù)
List<Object> eventQueue = postingState.eventQueue;
// 把 post 的事件添加到事件隊列
eventQueue.add(event);
// 如果沒有處在事件發(fā)布狀態(tài)帖鸦,那么開始發(fā)送事件并一直保持發(fā)布狀態(tài)
if (!postingState.isPosting) {
// 是否是主線程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
// isPosting = true
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;
}
}
}
- 首先根據(jù) currentPostingThreadState 獲取當(dāng)前線程狀態(tài) postingState 芝薇。currentPostingThreadState 其實就是一個 ThreadLocal 類的對象,不同的線程根據(jù)自己獨有的索引值可以得到相應(yīng)屬于自己的 postingState 數(shù)據(jù)作儿。
- 然后把事件 event 加入到 eventQueue 隊列中排隊洛二。
- 循環(huán)遍歷 eventQueue ,取出事件發(fā)送事件攻锰。發(fā)送單個事件是調(diào)用 postSingleEvent(Object event, PostingThreadState postingState) 方法晾嘶。
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
// 得到事件的Class
Class<?> eventClass = event.getClass();
// 是否找到訂閱者
boolean subscriptionFound = false;
// 如果支持事件繼承,默認(rèn)為支持
if (eventInheritance) {
// 查找 eventClass 的所有父類和接口
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
// 依次向 eventClass 的父類或接口的訂閱方法發(fā)送事件
// 只要有一個事件發(fā)送成功娶吞,返回 true 垒迂,那么 subscriptionFound 就為 true
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
// 發(fā)送事件
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
// 如果沒有訂閱者
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// 得到Subscription 列表
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
// 遍歷 subscriptions
for (Subscription subscription : subscriptions) {
//
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
// 發(fā)送事件
postToSubscription(subscription, event, postingState.isMainThread);
// 是否被取消了
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
// 如果被取消,則跳出循環(huán)
if (aborted) {
break;
}
}
return true;
}
return false;
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
// 根據(jù)不同的線程模式執(zhí)行對應(yīng)
switch (subscription.subscriberMethod.threadMode) {
// 和發(fā)送事件處于同一個線程
case POSTING:
invokeSubscriber(subscription, event);
break;
// 主線程
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
// 子線程
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
// 和發(fā)送事件處于不同的線程
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
到這里我們基本就把核心的內(nèi)容解析完了妒蛇,重點就是去遍歷 typesBySubscriber 找出滿足需求的然后反射執(zhí)行對應(yīng)的方法机断,至于在哪里執(zhí)行這個就需要判斷 threadMode。
3.EventBus.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 {
Log.w(TAG, "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) {
// 獲取事件類的所有訂閱信息列表绣夺,將訂閱信息從訂閱信息集合中移除吏奸,同時將訂閱信息中的active屬性置為FALSE
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) {
// 將訂閱信息激活狀態(tài)置為FALSE
subscription.active = false;
// 將訂閱信息從集合中移除
subscriptions.remove(i);
i--;
size--;
}
}
}
}