此文章是建立在已經掌握EventBus的使用方法基礎上的,不會的參考官網
我們通過2步來講解,首先是注冊、接收回調與發送消息,然后講解一下解除注冊
第一步:
1、注冊類:注冊與回調方法
EventBus.getDefault().register(this);
/**
* 注解回調的方法
* @param messageEvent
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void optionEvent(MessageEvent messageEvent){
textView.setText(messageEvent.getMessage());
}
此時我們查看一下源碼
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
我們知道注冊時回調的方法名是可以隨便起的,原因就是上面第3句(findSubscriberMethods),有一個方法可以遍歷處理此類的所有使用過@Subscribe此注解的方法集合。
接著可以看到,下面是遍歷所有需要回調的方法集,調用了subscribe方法,我們來看一下此方法,代碼太長我們貼主要代碼
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;
}
}
這里我們看到有一個subscriptionsByEventType成員變量,此變量是以EventType為key,而Value是Subscription集合,我們通過源碼可以看到,這里是通過EventType把所有注冊類下面相同參數的方法進行了分組。
也就是說注冊類下面有幾個接收回調的方法,就有幾個Subscription類對象,而且同一個類可以寫多個相同結果回調方法,方法名可以不同,源碼都會先進行分組后放進subscriptionsByEventType集合中。
2、發送消息
MessageEvent messageEvent = new MessageEvent(editText.getText().toString());
EventBus.getDefault().post(messageEvent);
我們看一下源碼
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;
}
我們可以看到,這里就是遍歷subscriptionsByEventType此集合,通過傳入的EventType得到所有注冊過以此方法為參數的對象,通過反射調用對象下面的方法。
第二步:取消注冊
EventBus.getDefault().unregister(this);
我們看一下源碼
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());
}
}
我們可以看到,取消注冊是通過遍歷typesBySubscriber集合,來把添加到subscriptionsByEventType集合的數值移除掉,然后再從typesBySubscriber移除掉(因為注冊傳入的是this,所以一定要進行解除注冊,否則會造成內存泄漏),我們回頭在看一下typesBySubscriber集合,是在注冊時集合加入的
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
此集合是以注冊類對象為key,EventType為value進行存儲,目的就是為了解除注冊時方便從subscriptionsByEventType集合中移除注冊的方法。
講到這里,整個EventBus處理的流程是講完了,這次是第一次完整的自己分析源碼,講一下感受:
當我們要研究一個項目的源碼時,開始一定要先會使用此項目,然后通過使用的入口,進行Debug查看調用流程,然后看源碼的時候剛開始不要太細鉆研每個調用方法是干什么用的,要先理清整個脈絡,然后再回頭單塊攻克主要的成員變量是干什么用的,為什么這么用,如果理不清楚,可以用筆寫一下,每個值是干什么用的,真的很有用!!
最后貼一下我梳理時的筆記,字有點丑介意的話,請....你懂得