EventBus的基本用法
注冊(cè)事件
EventBus.getDefault().register(this);
解除注冊(cè)
EventBus.getDefault().unregister(this);
發(fā)送事件
EventBus.getDefault().post(event);
處理事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void XXX(Object event) {
...
}
注解@Subscribe
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
/**
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
*/
boolean sticky() default false;
/** Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s! */
int priority() default 0;
}
這是一個(gè)自定義的運(yùn)行時(shí)注解薛闪,有三個(gè)屬性勺良,threadMode铅檩、sticky守呜、priority。
threadMode表示處理事件所在的線程躬翁,有POSTING焦蘑、MAIN、BACKGROUND和ASYNC四種線程模型盒发,默認(rèn)為POSTING例嘱。
sticky是否是粘性事件,默認(rèn)為false宁舰。
priority為優(yōu)先級(jí)拼卵,默認(rèn)值為0,值越大優(yōu)先級(jí)越高蛮艰。
EventBus的getDefault()
EventBus.getDefault()采用單例模式腋腮,創(chuàng)建一個(gè)EventBus對(duì)象,初始化了subscriptionsByEventType和typesBySubscriber兩個(gè)HashMap壤蚜,用以存儲(chǔ)訂閱者即寡、訂閱方法和訂閱事件的相關(guān)信息。
//這是一個(gè)單例模式
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
//創(chuàng)建了一個(gè)EventBus對(duì)象
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
//一個(gè)HashMap仍律,以事件類型eventType為key嘿悬,以存儲(chǔ)了訂閱者和訂閱方法的集合CopyOnWriteArrayList<Subscription>為value
subscriptionsByEventType = new HashMap<>();
//一個(gè)HashMap实柠,以訂閱者subscriber為key水泉,以訂閱者所訂閱的事件類型eventType的集合List<Class<?>>為value
typesBySubscriber = new HashMap<>();
//粘性事件相關(guān)的集合,這里不對(duì)粘性事件做分析窒盐,有興趣的自行學(xué)習(xí)
stickyEvents = new ConcurrentHashMap<>();
//主線線程事件發(fā)送者
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
//后臺(tái)線程事件發(fā)送者
backgroundPoster = new BackgroundPoster(this);
//異步線程事件發(fā)送者
asyncPoster = new AsyncPoster(this);
...
}
注冊(cè)register
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//獲取訂閱者的訂閱方法的集合草则,后面有對(duì)findSubscriberMethods的描述
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
//Subscription封裝了訂閱者subscriber和訂閱方法subscriberMethod
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
//subscriptions若為空,先初始化蟹漓,subscriptions已包含newSubscription炕横,說明已被注冊(cè)過,拋異常
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++) {
//按優(yōu)先級(jí)把newSubscription添加到subscriptions葡粒,即添加到subscriptionsByEventType
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);
}
//把eventType添加到subscribedEvents份殿,即添加到typesBySubscriber
subscribedEvents.add(eventType);
//粘性事件相關(guān)處理
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);
}
}
}
從上面代碼可以看出膜钓,注冊(cè)其實(shí)就是把當(dāng)前訂閱者相關(guān)的所有newSubscription存入subscriptionsByEventType,把當(dāng)前訂閱者訂閱的所有eventType存入typesBySubscriber卿嘲。
因?yàn)閚ewSubscription包含了訂閱者subscriber和訂閱方法subscriberMethod颂斜,subscriptionsByEventType的key為事件類型eventType,
所以在subscriptionsByEventType中可以根據(jù)事件類型eventType獲取所有的類型為eventType的訂閱方法subscriberMethod拾枣。因?yàn)閠ypesBySubscriber的key為訂閱者subscriber沃疮,所以在typesBySubscriber中可以根據(jù)訂閱者subscriber獲取訂閱者訂閱的所有的事件類型eventType。
subscriberMethodFinder.findSubscriberMethods(subscriberClass)
方法findSubscriberMethods是為了獲取訂閱者的訂閱方法的集合List<SubscriberMethod>梅肤,查看findSubscriberMethods這個(gè)方法的源碼可以發(fā)現(xiàn)如果不使用索引司蔬,最終會(huì)調(diào)用findUsingReflectionInSingleClass方法,而默認(rèn)是不使用索引的姨蝴,對(duì)索引感興趣的請(qǐng)自行學(xué)習(xí)俊啼,下面是findUsingReflectionInSingleClass方法的源碼:
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();
//方法名前有public,沒有abstract左医、static
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
//方法只有一個(gè)參數(shù)
if (parameterTypes.length == 1) {
//方法的@Subscribe注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
//獲取注解中的threadMode
ThreadMode threadMode = subscribeAnnotation.threadMode();
//findState.subscriberMethods是一個(gè)List<SubscriberMethod>集合吨些,創(chuàng)建訂閱方法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");
}
}
}
從上面源碼中可以看出,集合findState.subscriberMethods就是我們要獲取的集合炒辉,最后通過getMethodsAndRelease(FindState findState)從FindState中獲取這個(gè)集合
解除注冊(cè)u(píng)nregister
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
//根據(jù)訂閱者subscriber獲取訂閱者訂閱的所有的事件類型
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
//從subscriptionsByEventType中移除訂閱者對(duì)應(yīng)的subscription
unsubscribeByEventType(subscriber, eventType);
}
//移除訂閱者訂閱的所有的事件類型
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
/*
*從subscriptionsByEventType中移除訂閱者對(duì)應(yīng)的subscription豪墅,subscription包含subscriberMethod,
*所以其實(shí)是從subscriptionsByEventType中移除訂閱者對(duì)應(yīng)的處理eventType類型事件的方法subscriberMethod
*/
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//獲取所有的類型為eventType的Subscription的集合
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);
//判斷是否是當(dāng)前訂閱者subscriber
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
從上面代碼可以看出,解除注冊(cè)其實(shí)就是從typesBySubscriber中移除訂閱者訂閱的所有的事件類型eventType黔寇,從subscriptionsByEventType中移除所有當(dāng)前訂閱者對(duì)應(yīng)的處理eventType類型事件的方法subscriberMethod偶器。
發(fā)送事件post
post方法最終調(diào)用的是postToSubscription方法,源碼如下:
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);
}
}
從上面可以看出發(fā)送者和處理函數(shù)在相同線程直接調(diào)用invokeSubscriber缝裤,不相同時(shí)屏轰,分別調(diào)用mainThreadPoster.enqueue、backgroundPoster.enqueue和asyncPoster.enqueue憋飞。其中mainThreadPoster.enqueue是通過Handler將消息發(fā)送到主線程最終再調(diào)用invokeSubscriber霎苗,而backgroundPoster.enqueue和asyncPoster.enqueue都是通過調(diào)用線程池的線程的run方法最終調(diào)用invokeSubscriber,所以postToSubscription方法最終調(diào)的都是invokeSubscriber方法榛做,只是所在線程不同罷了唁盏。
從invokeSubscriber的源碼可以看出,它通過反射調(diào)用處理事件的方法检眯,方法的參數(shù)是event厘擂。
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);
}
}
最后
EventBus維護(hù)了subscriptionsByEventType和typesBySubscriber兩個(gè)HashMap,其中typesBySubscriber的key為訂閱者subscriber锰瘸,value為訂閱者訂閱的所有的事件類型eventType的集合刽严,便于注冊(cè)和解除注冊(cè)時(shí)添加移除當(dāng)前訂閱者訂閱的事件類型。subscriptionsByEventType的key為eventType避凝,value為由訂閱者和處理eventType類型事件的方法subscriberMethod組成的subscription對(duì)象的集合舞萄,便于發(fā)送事件時(shí)通過事件類型eventType獲取處理對(duì)應(yīng)事件的方法眨补,最后通過反射機(jī)制調(diào)用該方法。