本文的源碼使用到EventBus3.2.0版本
本文所示的源碼将會忽略與核心邏輯無關的代碼,被忽略的代碼将使用省略号表示
以下為eventBus最簡單的使用代碼:
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// 注冊eventbus
EventBus.getDefault().register(this);.
// 發送消息
EventBus.getDefault().post(new Object());
}
// 添加消息監聽注解
@Subscribe()
public void onEvent(Event event){
Log.d("test","接收到消息");
}
}
該代碼運作後将會列印,“接收到消息”;
EventBus注冊原理
那麼接下來分析代碼“EventBus.getDefault().register(this)”,幹了什麼
public void register(Object subscriber) {
// 擷取訂閱者的class對像
Class<?> subscriberClass = subscriber.getClass();
// 擷取所有帶有注解“@Subscribe”的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
...
}
我們繼續進入“subscriberMethodFinder.findSubscriberMethods(subscriberClass)”方法中:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
...
if (ignoreGeneratedIndex) {
//預設走這裡
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
....
}
// 命名知意,使用反射方式查找
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
...
findUsingReflectionInSingleClass(findState);
...
return getMethodsAndRelease(findState);
}
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
...
// 擷取訂閱者對象的所有方法
methods = findState.clazz.getDeclaredMethods();
...
//周遊所有方法
for (Method method : methods) {
...
// 核心!核心!核心!
Class<?>[] parameterTypes = method.getParameterTypes();
// 過濾隻有一個參數的方法
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
// 找出帶有“Subscribe”注解的方法
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
// 建立一個訂閱者方法對象,并緩存到subscriberMethods隊列中
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
}
...
}
}
好了,簡單來說,EventBus注冊其實就是找出被注冊對象中所有帶有@Subscribe注解的方法,并緩存起來!
EventBus發送消息原理
我們一起來看看 "EventBus.getDefault().post(new Object())"幹了什麼
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
// 将消息加入到隊列中
eventQueue.add(event);
...
while (!eventQueue.isEmpty()) {
// 周遊隊列,并執行postSingleEvent
postSingleEvent(eventQueue.remove(0), postingState);
}
...
}
}
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
// 擷取event的class對象,本事例是Object,實際使用将會是自定義的一個實體類
Class<?> eventClass = event.getClass();
... //剔除了所有非核心代碼
// lookupAllEventTypes方法實際是找出event對象的所有基類,這裡不多介紹,有興趣的自己跟源碼
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);
}
...
}
// 核心!核心!核心
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// 根據event對象,擷取所有訂閱者方法
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
//周遊
for (Subscription subscription : subscriptions) {
...
postToSubscription(subscription, event, postingState.isMainThread);
...
}
return true;
}
return false;
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
// 忽略各種線程排程代碼
...
invokeSubscriber(subscription, event);
...
}
//最終到這裡
void invokeSubscriber(Subscription subscription, Object event) {
...
// 反射執行訂閱者的方法,并傳遞event對象
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
...
}
是以,簡單來說,EventBus消息發送就是通過event對象找出在注冊時所緩存的訂閱者方法,然後執行!
原理總結
一句話,注冊就是以反射方式緩存訂閱者方法,發送消息就是以反射方式執行已緩存的訂閱者方法。
核心實作原理僅用到Java反射機制!
OK,就這麼多!用幫助的話,點個贊!