EventBus 原始碼分析(上篇)
可用於應用內的訊息事件傳遞,方便快捷,耦合性低
1.基本用法
public class EventBusMain extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.content_main); EventBus.getDefault().register(this); } - 訂閱的事件 onEvent1 @Subscribe public void onEvent1(RemindBean bean){ } - 訂閱的事件 onEvent2 @Subscribe public void onEvent2(UserInfo bean){ } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } }
需要傳送訊息傳遞的時候:
EventBus.getDefault().post(new RemindBean())
2.原始碼解讀
放上官網的一張原理圖,感覺挺清晰的:

image.png
釋出訊息的一方( Publisher
),只需要 post
一個 event
之後就不用管了, EventBus
內部會將 event
逐一分發給訂閱此 event
的訂閱者( Subscriber
). 不錯就是這樣一個東西。
還記得以往我要實現兩個不同的 activity
之間要傳遞一些資料的時候,我都是通過定義一個 interface
的形式完成,時間一長,定義的介面一堆,在回顧檢視程式碼也確實不夠美觀。好了話不多說,看下大家都在用的 Eventbus
.
3.首先
EventBus.getDefault().register(this);
getDefault()
:
EventBus 是一個單例模式,懶漢式,雙重判斷 /** Convenience singleton for apps using a process-wide EventBus instance. */ public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
register
是什麼意思呢,就是就跟你訂閱報紙一樣,報社需要確定幾個重要的問題:
Subscriber Event
就是我認為比較重要的,那麼 register
這一步就是 Subscriber
告訴 報社,訂閱的 event
public void register(Object subscriber) { - 1.先拿到這個訂閱者(subscriber)類的位元組碼 Class<?> subscriberClass = subscriber.getClass(); - 2. 通過這個類的位元組碼,拿到所有的訂閱的 event,存放在List中 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { - 3. 迴圈遍歷所有的訂閱的方法,完成subscriber 和 subscriberMethod 的關聯 for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
我們看下這個如何根據 subscriberClass
找到這個訂閱的 method
的, findSubscriberMethods
:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { - 1.先從快取中取 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); - 2. 第一次肯定 null if (subscriberMethods != null) { return subscriberMethods; } - 3. 查詢預設也是false,感興趣的可以看下 if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else { - 4. 所以是走這裡 subscriberMethods = findUsingInfo(subscriberClass); } if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation"); } else { - 5. 找到之後新增到快取中,key是 subscriber ;value 是:methods METHOD_CACHE.put(subscriberClass, subscriberMethods); return subscriberMethods; } }
看下: findUsingInfo(subscriberClass)
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { - 1. 我認為就是準備一個查詢結果得儲存物件 FindState findState = prepareFindState(); - 2. 將訂閱者的subscriberClass 儲存起來,儲存在一個FindState 類中的subscriberClass 同時賦值給clazz變數中,以下程式碼能夠看出 //void initForSubscriber(Class<?> subscriberClass) { //this.subscriberClass = clazz = subscriberClass; //} findState.initForSubscriber(subscriberClass); while (findState.clazz != null) {進入迴圈中 //獲取subscriberInfo 資訊,返回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 { - 3. 進入到這裡了 findUsingReflectionInSingleClass(findState); } - 4. 查詢父類中的方法 findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }
findUsingReflectionInSingleClass
如下:
private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { // This is faster than getMethods, especially when subscribers are fat classes like Activities - 1. 通過訂閱者的位元組碼查詢當前類中所有生命的方法 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; } - 2. 迴圈遍歷所有的方法 for (Method method : methods) { - 3. 獲取方法的修飾符 int modifiers = method.getModifiers(); - 4.判斷修飾符,訂閱方法的修飾符不能是private,static if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { - 5. 獲取方法的所有的引數 Class<?>[] parameterTypes = method.getParameterTypes(); - 6.判斷引數的個數,只能有1個引數,訂閱方法中 if (parameterTypes.length == 1) { - 7.獲取方法上具有subscribe 註解 Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); - 8.含有subscribe註解的方法,就是該類訂閱的方法,其它不符合的可能就是普通的方法 if (subscribeAnnotation != null) { - 9. 獲取第一個引數eventType Class<?> eventType = parameterTypes[0]; if (findState.checkAdd(method, eventType)) { - 10. 獲取註解的mode,就是我們在註解上標識的, 有mainThread,Posting,background,async ThreadMode threadMode = subscribeAnnotation.threadMode(); - 11. 將訂閱方法的一系列資訊(方法名稱,threadMode,優先順序,是否是粘性等)新增到集合subscriberMethods中去 findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { - 12. 引數是多個的時候丟擲異常 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)) { - 13. 方法的修飾符不是public的,丟擲異常 String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } }
這樣我們將所有信息都儲存到 findState
類中去了。再回頭看我們原先那個方法,到第三步了:
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { - 1. 我認為就是準備一個查詢結果得儲存物件 FindState findState = prepareFindState(); - 2. 將訂閱者的subscriberClass 儲存起來,儲存在一個FindState 類中的subscriberClass 同時賦值給clazz變數中,以下程式碼能夠看出 //void initForSubscriber(Class<?> subscriberClass) { //this.subscriberClass = clazz = subscriberClass; //} findState.initForSubscriber(subscriberClass); while (findState.clazz != null) {進入迴圈中 //獲取subscriberInfo 資訊,返回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 { - 3. 進入到這裡了,上面已經分析所有資訊儲存到findState中 findUsingReflectionInSingleClass(findState); } - 4. 查詢父類中的方法 findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }
在這個 getMethodsAndRelease(findState)
:
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) { - 1. 取出裡面的subscriberMethods List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods); findState.recycle(); synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { if (FIND_STATE_POOL[i] == null) { FIND_STATE_POOL[i] = findState; break; } } } - 2. 返回集合 return subscriberMethods; }
至此,我們知道了根據訂閱者( subscriber
)的 clazz
找到了所有訂閱的方法事件
methods
回到最初的第一步 register
:
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); - 2. 完成 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { - 3.迴圈遍歷所有的訂閱方法和訂閱者之間建立關聯 subscribe(subscriber, subscriberMethod); } } }
subscribe(subscriber, subscriberMethod)
方法:
// Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { - 1. 訂閱方法的eventType的位元組碼 Class<?> eventType = subscriberMethod.eventType; - 2. 訂閱者和訂閱方法封裝成一個Subscription 物件 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); - 3. subscriptionsByEventType 第一次也是null ,根據eventType CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); - 4. 第一次肯定為null if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); - 5. key 為 eventType, value 是subscriptions物件 subscriptionsByEventType.put(eventType, subscriptions); } else { - 丟擲異常 if (subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } - 6. 獲取所有新增的subscriptions int size = subscriptions.size(); for (int i = 0; i <= size; i++) { - 7. 會判斷每個訂閱方法的優先順序,新增到這個 subscriptions中,按照優先順序 if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } } - 8.獲取訂閱的方法集合 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); - 9. 為空新增到 typesBySubscriber typesBySubscriber.put(subscriber, subscribedEvents); } - 10. 訂閱事件新增到subscribedEvents集合中去 subscribedEvents.add(eventType); - 11. 判斷是否是粘性事件的關聯 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); } } }
到此,如果你跟著我一步步看到這裡,應該大概明白一些了,還有一部分沒完,就是 register
前半部分完成訂閱,儲存等工作;剩下 post(event)
方法就是將 event
分發給相應訂閱過此事件的訂閱者了。