最近在項(xiàng)目中使用了EventBus(3.0),覺得非常好用,于是就看了一些關(guān)于EventBus源碼分析的文章,現(xiàn)在記錄下它的基本使用方法和看源碼過程中分析的一些問題。EventBus源碼地址

EventBus是什么?
EventBus是一個(gè)Android事件發(fā)布和訂閱的框架,通過解耦發(fā)布者和訂閱者來簡(jiǎn)化Android事件傳遞。
EventBus是干什么的?

事件傳遞既可以用于Android四大組件間通訊,也可以用于異步線程和主線程間通訊等。傳統(tǒng)的事件傳遞方式包括:Handler、BroadcastReceiver、Interface回調(diào),而EventBus就是用來傳遞事件的,相比傳統(tǒng)的方式,它代碼簡(jiǎn)潔,使用簡(jiǎn)單,并將事件發(fā)布和訂閱充分解耦。
基本使用方法
添加依賴庫(kù)
//在app下的build.gradle中添加下面的依賴
compile 'org.greenrobot:eventbus:3.0.0'
注冊(cè)訂閱事件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
}
取消注冊(cè)訂閱事件
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
發(fā)布事件
EventBus.getDefault().post(Object obj);
訂閱事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(Object obj) {
}
看吧,使用起來還是挺簡(jiǎn)單的,訂閱者真正需要處理邏輯的就是在有注解@subscribe的方法onEvent(Object obj)中去按照我們自己的需求去處理,當(dāng)然這里方法名不一定是onEvent了,我是受2.4版本影響,習(xí)慣了把方法名寫成onEvent,在3.0版本中可以隨意寫,但是參數(shù)的class類型必須要跟發(fā)布者post的參數(shù)的class類型一致。
使用場(chǎng)景
比如有一個(gè)列表頁面,每個(gè)item上都有評(píng)論數(shù),點(diǎn)贊數(shù)和點(diǎn)贊狀態(tài),點(diǎn)進(jìn)去到詳情頁,用戶可以進(jìn)行一些操作,評(píng)論,點(diǎn)贊,這時(shí)候詳細(xì)頁的評(píng)論數(shù)點(diǎn)贊數(shù)和點(diǎn)贊狀態(tài)我們可以立即更新,但是當(dāng)我們回到列表頁面的時(shí)候,也需要更新UI啊,之前也說了,傳統(tǒng)的事件傳遞方式有Handler,BroadcastReceiver,以及Interface回調(diào)等,如果不使用EventBus的話,我會(huì)考慮使用廣播的方式或者用startActivityForResult來打開詳細(xì)頁,等到從詳細(xì)頁返回到列表頁時(shí),將操作后的對(duì)象傳遞回來,然后在onActivityResult方法中去處理更新UI。但是這種方法的弊端在于只有在返回到上一個(gè)界面時(shí)才會(huì)將事件傳遞回來,不能達(dá)到立即更新的目的。
線程模式
上面說過,只有使用注解@Subscribe(threadMode = ThreadMode.MAIN)標(biāo)明的方法才是訂閱者需要處理邏輯的地方。那這個(gè)threadMode是什么呢?它其實(shí)是指定訂閱者處理事件的線程,EventBus總共有四種線程模式,分別是:
ThreadMode.MAIN:表示無論事件是在哪個(gè)線程發(fā)布出來的,該事件訂閱方法onEvent都會(huì)在UI線程中執(zhí)行,這個(gè)在Android中是非常有用的,因?yàn)樵贏ndroid中只能在UI線程中更新UI,所有在此模式下的方法是不能執(zhí)行耗時(shí)操作的。
ThreadMode.POSTING:表示事件在哪個(gè)線程中發(fā)布出來的,事件訂閱函數(shù)onEvent就會(huì)在這個(gè)線程中運(yùn)行,也就是說發(fā)布事件和接收事件在同一個(gè)線程。使用這個(gè)方法時(shí),在onEvent方法中不能執(zhí)行耗時(shí)操作,如果執(zhí)行耗時(shí)操作容易導(dǎo)致事件分發(fā)延遲。
ThreadMode.BACKGROUND:表示如果事件在UI線程中發(fā)布出來的,那么訂閱函數(shù)onEvent就會(huì)在子線程中運(yùn)行,如果事件本來就是在子線程中發(fā)布出來的,那么訂閱函數(shù)直接在該子線程中執(zhí)行。
ThreadMode.ASYNC:使用這個(gè)模式的訂閱函數(shù),那么無論事件在哪個(gè)線程發(fā)布,都會(huì)創(chuàng)建新的子線程來執(zhí)行訂閱函數(shù)。
ASYNC相比前三者不同的地方是可以處理耗時(shí)的操作,其采用了線程池,且是一個(gè)異步執(zhí)行的過程,即事件的訂閱者可以立即得到執(zhí)行。雖然BACKGROUND也采用了線程池,但它每次只能執(zhí)行一個(gè)任務(wù),就是不會(huì)異步執(zhí)行。所以一般是更新UI的事件,就使用ThreadMode.MAIN,需要請(qǐng)求網(wǎng)絡(luò)的事件就使用ThreadMode.AYSNC,。
final class BackgroundPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
backgroundPoster通過enqueue方法,將當(dāng)前的訂閱者添加至隊(duì)列PendingPostQueue
中,是否立即執(zhí)行,則需要判斷當(dāng)前隊(duì)列是否還有正在執(zhí)行的任務(wù),若沒有的話,則立即執(zhí)行,若還有執(zhí)行任務(wù)的話,則只進(jìn)行隊(duì)列的添加。這樣,保證了后臺(tái)任務(wù)永遠(yuǎn)只會(huì)在一個(gè)線程執(zhí)行。
class AsyncPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
AsyncPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
}
AsyncPoster是直接通過線程池調(diào)用執(zhí)行,相比BackgroundPoster執(zhí)行來說,則沒有等待的過程。
final class HandlerPoster extends Handler {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
HandlerPoster是我們?cè)偈煜げ贿^的Handler消息機(jī)制了,它會(huì)將每個(gè)訂閱事件傳遞到UI線程中進(jìn)行處理。這里就不多說了。
源碼分析
EventBus的事件總線
在EventBus中,真正的訂閱對(duì)象是SubscriberMethod,包含了相應(yīng)的Method類,以及事件參數(shù)類型Class<?> eventType,其他就是線程,優(yōu)先級(jí),是否Sticky信息。
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class<?> eventType;
final int priority;
final boolean sticky;
}
Sticky=true表示等到回到事件訂閱的界面時(shí)才開始傳遞消,而不是一post就開始傳遞,什么時(shí)候使用sticy呢?當(dāng)你希望你的事件不被馬上處理的時(shí)候。
事件總線,一般都對(duì)應(yīng)著一個(gè)集合,這個(gè)集合中的對(duì)象就是訂閱的事件,而EventBus中使用的是:
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
subscriptionsByEventType = new HashMap<>();
這里的Map集合采用的是一個(gè)HashMap集合,map的key對(duì)應(yīng)就是之前SubscriberMethod中的eventType, value則對(duì)應(yīng)著一個(gè)線程安全的List,List中存放的是包含訂閱對(duì)象Object及相應(yīng)訂閱方法SubscriberMethod的Subscription類:
final class Subscription {
final Object subscriber;
final SubscriberMethod subscriberMethod;
}
所以,EventBus內(nèi)部是用了一個(gè)線程安全的List集合來維持所有的訂閱者,即事件總線集合。而注冊(cè)訂閱和取消注冊(cè)訂閱就是對(duì)這個(gè)List集合進(jìn)行增刪的過程。
注冊(cè)訂閱和取消注冊(cè)訂閱
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
首先EventBus會(huì)根據(jù)訂閱類的Class去這個(gè)類中查找處理訂閱事件的方法,SubscriberMethodFinder這個(gè)類看名字我們就知道它是干什么用的了,等會(huì)在細(xì)說。下面我們看看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);
}
}
}
從這個(gè)方法我們可以看到每一個(gè)eventType 都對(duì)應(yīng)一個(gè)CopyOnWriteArrayList<Subscription>,不過這樣讀源碼太不好理解了,結(jié)合我Demo中的例子來說,MainActivity中的subscriberMethod就是onEvent(NewsModel newsModel)方法,所以eventType就是NewsModel類,而subscriber就是MainActivity的實(shí)例,他倆組合成了一個(gè)訂閱者Subscription,然后把eventType作為key,訂閱了NewsModel這類事件的訂閱者的集合作為value存儲(chǔ)在一個(gè)HashMap中,最后根據(jù)優(yōu)先級(jí)priority將newSubscription這個(gè)最新的訂閱者添加到訂閱列表中。也就是說在一個(gè)Activity頁面類,我們可以有多個(gè)SubscriberMethod,就像下面這樣:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(NewsModel newsModel) {
newsList.set(clickPosition, newsModel);
mAdapter.notifyItemChanged(clickPosition);
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onEvent1(User user) {
}
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onEvent2(Person person) {
}
取消注冊(cè)訂閱則是將該事件類型的訂閱者從事件總線集合中移除:
/** 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) {
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--;
}
}
}
}
事件消費(fèi)和發(fā)布事件
這里通過EventBus的post(Object event)方法,進(jìn)行事件的發(fā)出。緊接著EventBus的總線List中找出訂閱了這個(gè)event的方法Subscription,然后根據(jù)method指定的不同線程信息,將這個(gè)方法的調(diào)用,放置在相應(yīng)線程中調(diào)用,看看EventBus中的post方法:
/** 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 = Looper.getMainLooper() == Looper.myLooper();
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;
}
}
}
順著postSingleEvent方法看下來,我們會(huì)發(fā)現(xiàn)最終將會(huì)調(diào)用方法postToSubscription將發(fā)布事件傳遞到訂閱者這里來。
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 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);
}
}
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)用訂閱者的消費(fèi)該事件的方法。也許當(dāng)你看上面postToSubscription方法時(shí)會(huì)發(fā)現(xiàn)threadMode是MAIN、BACKGROUND或者ASYNC時(shí),都有用各自縣城的poster調(diào)用enqueue方法,其實(shí)仔細(xì)一層層看下去你會(huì)發(fā)現(xiàn)到最后還是調(diào)用了invokeSubscriber方法。所以,最終的消費(fèi)方法調(diào)用就是這行代碼:
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
訂閱者已經(jīng)被封裝地非常完美,這樣,我們?cè)谑褂貌煌木€程調(diào)度策略就很簡(jiǎn)單了,隨意指定一個(gè)ThreadMode,即可在指定線程中調(diào)用。
看到這里,也許你會(huì)發(fā)現(xiàn)有個(gè)很大的疑問:SubscriberMethod信息是怎么生成的?其實(shí)就是加了注解@Subscribe的方法。我們可以通過在運(yùn)行時(shí)采用反射的方法,獲取相應(yīng)添加了注解的方法,再封裝成為SubscriberMethod。也就是前面我提到的SubscriberMethodFinder類來獲取消費(fèi)事件方法??丛创a,真正在運(yùn)行時(shí)利用反射去查找SubscriberMethod的代碼:
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");
}
}
}
對(duì)于我們開發(fā)者來說,使用反射帶來的性能消耗,是必須要考慮到的。在3.0的版本,EventBus加入了apt處理的邏輯,有個(gè)Subscriber Index的介紹,主要是通過Apt在編譯期根據(jù)注解直接生成相應(yīng)的信息,來避免在運(yùn)行時(shí)通過反射來獲取。使用方法如下:
buildscript {
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
apt {
arguments {
eventBusIndex "com.example.myapp.MyEventBusIndex"
}
}

上面的配置除了第一條是在project的build.gradle中添加,其余的都是在moudle中的build.gradle中添加,具體的大家可以看我的Demo中配置方法。當(dāng)我們?cè)俅尉幾g之后,系統(tǒng)會(huì)自動(dòng)為我們生成MyEventBusIndex這個(gè)類,然后我們將它設(shè)置給EventBus:
EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
或者是這樣:
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();
MyEventBusIndex這個(gè)生成的索引類實(shí)際上會(huì)實(shí)現(xiàn)SubscriberInfoIndex這個(gè)接口:
public interface SubscriberInfoIndex {
SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);
}
從接口中可以看出,這個(gè)Index類只提供了一個(gè)方法getSubsriberInfo,這個(gè)方法需要我們傳入訂閱者所在的class類,然后獲得一個(gè)SubscriberInfo的類,其類結(jié)構(gòu)如下:
public interface SubscriberInfo {
Class<?> getSubscriberClass();
SubscriberMethod[] getSubscriberMethods();
SubscriberInfo getSuperSubscriberInfo();
boolean shouldCheckSuperclass();
}
從接口中的方法即可獲取所需的所有SubscriberMethod信息。而這只是一個(gè)獲取單個(gè)類的方法,而apt生成的MyEventBusIndex中,會(huì)將所有的這些class及SubscriberInfo保存在靜態(tài)變量hashMap結(jié)構(gòu),這樣就達(dá)到了避免運(yùn)行期反射獲取生成訂閱方法的性能問題。而變成另外一個(gè)流程:訂閱類在注冊(cè)的時(shí)候,直接通過HashMap中的訂閱類,獲取到SubscriberInfo,進(jìn)而獲取到所有的SubscerberMethod,并封裝為Subscription,被添加到事件總線中。這樣,在引入了apt之后,EventBus的性能問題就得以解決了。
說完了性能問題,還得接著說SubscriberMethodFinder這個(gè)類,它會(huì)根據(jù)訂閱類class信息,來獲取SubscriberMethod,EventBus提供了兩種方式進(jìn)行獲?。?/p>
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
- 如果不使用生成的索引來查找,就采用
findUsingReflection(subscriberClass)方法進(jìn)行反射來獲取。 - 使用生成的索引來查找,就采用
findUsingInfo(subscriberClass)方法在apt中進(jìn)行查找獲取。
而這個(gè)ignoreGeneratedIndex默認(rèn)是false的,如果沒有在項(xiàng)目中引入apt則將強(qiáng)制使用反射方式查找。
/** Forces the use of reflection even if there's a generated index (default: false). */
public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
this.ignoreGeneratedIndex = ignoreGeneratedIndex;
return this;
}
在查找SubscriberMethod時(shí),EventBus封裝了一個(gè)類FindState對(duì)查找的狀態(tài)值處理,結(jié)構(gòu)如下:
static class FindState {
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
}
其中有訂閱類subscriberClass,事件對(duì)象clazz,以及查找的結(jié)果subscriberMethods、subscriberInfo等,另外,還有一個(gè)判斷的標(biāo)志量skipSuperClasses,用來標(biāo)記是否需要進(jìn)行父類的查找。
無論是哪種查找方法,步驟都是一樣的,于是FindState將這些通用的步驟封裝起來,大致是這四步:
- initForSubscriber(Class<?> subscriberClass) 初始化訂閱類
- checkAdd(Method method, Class<?> eventType) 檢查方法合法性
- checkAddWithMethodSignature(Method method, Class<?> eventType) 檢查方法合法性
- moveToSuperclass() 是否需要查看父類中的訂閱方法
除了對(duì)查找結(jié)果的封裝,F(xiàn)indState還使用了緩存池:
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
EventBus指定了FindState的緩存池的大小為4,并使用一維的靜態(tài)數(shù)組,所以這里需要注意線程同步的問題。使用同步代碼塊從緩存池中取FindState,同樣,通過上面兩種方式獲取SubscriberMethod時(shí),也使用同步代碼塊將FindState放入了緩存池中。
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
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;
}
}
}
return subscriberMethods;
}
總結(jié)
分析了EventBus的源碼后,相信你會(huì)對(duì)它的工作方式更加清晰,簡(jiǎn)而言之,就是“發(fā)布者發(fā)布事件,訂閱者通過反射的方式根據(jù)發(fā)布事件的class類型查找SubscriberMethod,然后通過這個(gè)類來invoke訂閱類中處理對(duì)應(yīng)事件的方法”。它的引入大大簡(jiǎn)化了開發(fā)者需要做的工作,而且將訂閱者和發(fā)布者完全解耦,so趕緊用起來吧。