在我們開(kāi)發(fā)過(guò)程中进鸠,相信應(yīng)該有很多人使用過(guò)EventBus 3.0
结榄,這個(gè)確實(shí)方便了我們,少些了很多代碼,這是個(gè)優(yōu)秀的庫(kù)郊酒,我們接下來(lái)進(jìn)行對(duì)他剖析。
我們使用EventBus 3.0
的過(guò)程:
EventBus.getDefault().register()
EventBus.getDefault().post()
EventBus.getDefault().unregister()
我們先看看是怎么初始化的
/** 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;
}
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}
一個(gè)單例模式,接著點(diǎn)你會(huì)發(fā)現(xiàn)其實(shí)是利用的Builder
模式档冬,而框架內(nèi)部幫我們寫了一個(gè)EventBusBuilder
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
EventBusBuilder() {
}
在EventBusBuilder
初始化的時(shí)候除了對(duì)成員變量的一些初始化外瞧柔,其他的并沒(méi)有做什么操作。
接下來(lái)我們進(jìn)入register
函數(shù)
/**
* 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();
//根據(jù)subscriberClass 獲取訂閱的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
//遍歷訂閱
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
從這個(gè)函數(shù)我們可以很清晰的看到邏輯宋彼,首先根據(jù)subscriber(Activity,Fragment)
得到相應(yīng)的訂閱方法弄砍,然后在遍歷訂閱。這里代碼就不點(diǎn)進(jìn)去看了输涕,主要說(shuō)下框架的實(shí)現(xiàn)思路音婶。
采用了緩存加反射的方式,主要的參數(shù)和類為下:
METHOD_CACHE
:一個(gè)key
為訂閱者class
莱坎,value
為需要訂閱實(shí)現(xiàn)的方法的一個(gè)ConcurrentHashMap
衣式,這個(gè)HashMap
是為了保證線程并發(fā)安全。我們獲取的訂閱方法就會(huì)緩存到這里面檐什。
FindState
:顧名思義碴卧,這是一個(gè)檢測(cè)狀態(tài)的類,里面的參數(shù)為
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;
里面比較重要的幾個(gè)參數(shù):
SubscriberMethod
: 當(dāng)前訂閱對(duì)象(Activity,Fragment)
的訂閱方法實(shí)體乃正。
public class SubscriberMethod {
//方法
final Method method;
//模式
final ThreadMode threadMode;
//類型住册, 就是參數(shù)的類型 參數(shù)只能為1個(gè)
final Class<?> eventType;
final int priority;
final boolean sticky;
/** Used for efficient comparison */
String methodString;
subscriberMethods
:用來(lái)存儲(chǔ)當(dāng)前訂閱對(duì)象(Activity,Fragment)
內(nèi)的訂閱方法SubscriberMethod
。
anyMethodByEventType
: key
為參數(shù)類型(訂閱類型),value
為方法的一個(gè)緩存瓮具。
subscriberClassByMethodKey
:key
為 訂閱方法名+">"+參數(shù)類型name
,value
為訂閱方法的class
荧飞。
獲取訂閱方法的時(shí)候先判斷緩存里面是否存在凡人,不存在就獲取FindState
實(shí)例,根據(jù)反射獲取注解Subscribe(Activity,Fragment)
的方法叹阔,然后對(duì)FindState
實(shí)例進(jìn)行操作(anyMethodByEventType
和subscriberClassByMethodKey
得到相應(yīng)的值或添加到緩存)划栓,獲取到的訂閱方法集合其實(shí)就是FindState
實(shí)例里面的subscriberMethods
,最后在把獲取的訂閱方法集合加入緩存。
得到了訂閱方法集合接下來(lái)就遍歷subscriberMethods
:
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
// 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);
}
}
}
訂閱的時(shí)候条获,首先根據(jù)訂閱者(Activity Fragment)
和SubscriberMethod
得到一個(gè)Subscription
對(duì)象忠荞,這個(gè)類就是一個(gè)真正執(zhí)行信息傳遞的訂閱對(duì)象。
/*
* Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.greenrobot.eventbus;
final class Subscription {
final Object subscriber;
final SubscriberMethod subscriberMethod;
/**
* Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
* {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
*/
volatile boolean active;
Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
active = true;
}
@Override
public boolean equals(Object other) {
if (other instanceof Subscription) {
Subscription otherSubscription = (Subscription) other;
return subscriber == otherSubscription.subscriber
&& subscriberMethod.equals(otherSubscription.subscriberMethod);
} else {
return false;
}
}
@Override
public int hashCode() {
return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
}
}
接著把這個(gè)Subscription
對(duì)象添加CopyOnWriteArrayList
(CopyOnWriteArrayList
是一個(gè)適合用在讀多帅掘,寫少
的并發(fā)
應(yīng)用中委煤,它是一個(gè)線程安全的集合)然后將這個(gè)CopyOnWriteArrayList
添加到subscriptionsByEventType
里面,這個(gè)subscriptionsByEventType
是一個(gè)key
為訂閱方法的類型(方法函數(shù)的類型)修档,value
為一個(gè)存放Subscription
的CopyOnWriteArrayList
的HashMap
碧绞。接下來(lái)把訂閱方法的類型(參數(shù)類型)eventType
添加到一個(gè)ArrayList
里面,在將這個(gè)ArrayList
添加到typesBySubscriber
吱窝,typesBySubscriber
是一個(gè)key
為訂閱者對(duì)象(Fragment讥邻,Activity
),value
為ArrayList<Class<?>>
的HashMap
院峡,最后在判斷是否是sticky
,如果是的就將遍歷一個(gè)stickyEvents
的HashMap
兴使,然后根據(jù)key
(訂閱方法類型)發(fā)出消息。
我們看看unregister
/** 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--;
}
}
}
}
很簡(jiǎn)單照激,先根據(jù)訂閱者(Activity Fragment)
獲取到typesBySubscriber
里面的訂閱方法類型集合(List<Class<?>> subscribedTypes
),然后遍歷這個(gè)集合发魄,根據(jù)這個(gè)訂閱方法類型得到subscriptionsByEventType
里面的訂閱對(duì)象集合List<Subscription> subscriptions
,在遍歷這個(gè)subscriptions
集合,判斷subscription.subscriber == subscriber
然后移除俩垃,最后在移除typesBySubscriber
里面的這個(gè)訂閱對(duì)象(Fragment ,Activity )
励幼。
接下來(lái)我們看看post
,最終會(huì)走到這個(gè)函數(shù)
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);
}
}
/**
* Invokes the subscriber if the subscriptions is still active. Skipping subscriptions prevents race conditions
* between {@link #unregister(Object)} and event delivery. Otherwise the event might be delivered after the
* subscriber unregistered. This is particularly important for main thread delivery and registrations bound to the
* live cycle of an Activity or Fragment.
*/
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, 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);
}
}
在發(fā)送消息的時(shí)候根據(jù)消息類型(參數(shù)類型)
然后從上面的subscriptionsByEventType
里面取出相應(yīng)的數(shù)據(jù)進(jìn)行封裝成一個(gè)PendingPost
對(duì)象口柳,在根據(jù)反射invoke
對(duì)應(yīng)的方法即可苹粟,如果是MAIN
的話就通過(guò)Handler
進(jìn)行線程轉(zhuǎn)換,如果是BACKGROUND
并且是在主線程中調(diào)用或者是ASYNC
將會(huì)通過(guò)線程池來(lái)進(jìn)行線程切換跃闹。
接下來(lái)看看postSticky
:
/**
* Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
* event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}.
*/
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
這個(gè)其實(shí)我們?cè)谧?cè)的時(shí)候已經(jīng)分析了嵌削,當(dāng)調(diào)用這個(gè)函數(shù)的時(shí)候,將會(huì)將這個(gè)消息加到stickyEvents
里面辣卒,這個(gè)stickyEvents
是一個(gè)ConcurrentHashMap
,ConcurrentHashMap
是一個(gè)應(yīng)用于高并發(fā)的鍵值對(duì)掷贾,接著調(diào)用post
函數(shù)先把已經(jīng)注冊(cè)的觀察者的方法實(shí)現(xiàn)睛榄,接下來(lái)其他對(duì)象注冊(cè)的時(shí)候
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);
}
}
在這里將會(huì)調(diào)用荣茫。
還有一個(gè)優(yōu)先級(jí)priority
問(wèn)題,可以看到也是在注冊(cè)的時(shí)候
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;
}
}
其實(shí)也是很簡(jiǎn)單的原理场靴。源碼分析得也差不多了啡莉,具體的需要大家自己去查看源碼港准。
總結(jié),EventBus
的實(shí)現(xiàn)方式:反射 + 數(shù)據(jù)封裝 + 緩存 + 線程切換
通過(guò)查看EventBus
的源碼收獲了什么咧欣?
Builder
模式封裝參數(shù)
- 根據(jù)用處不同進(jìn)行對(duì)不同的類封裝浅缸,比如:
SubscriberMethodFinder
用于訂閱方法的查找;FindState
一個(gè)用SubscriberMethodFinder
查找的輔助類,里面封裝了一些數(shù)據(jù);SubscriberMethod
訂閱方法實(shí)體魄咕,就是通過(guò)注解的方法對(duì)應(yīng)的對(duì)象衩椒;Subscription
一個(gè)訂閱對(duì)象。 - 緩存
- 線程切換使用方式
- 反射用法熟悉加強(qiáng)
-
ThreadLocal
是一個(gè)關(guān)于創(chuàng)建線程局部變量的類哮兰。
通常情況下毛萌,我們創(chuàng)建的變量是可以被任何一個(gè)線程訪問(wèn)并修改的。而使用ThreadLocal
創(chuàng)建的變量只能被當(dāng)前線程訪問(wèn)喝滞,其他線程則無(wú)法訪問(wèn)和修改阁将。 -
CopyOnWriteArrayList
:是一個(gè)適合用在讀多,寫少的并發(fā)應(yīng)用中右遭,它是一個(gè)線程安全的集合 -
ConcurrentHashMap
:是一個(gè)應(yīng)用于高并發(fā)的鍵值對(duì)
人生苦短,要學(xué)會(huì)享受做盅!但是我還沒(méi)到應(yīng)該安于享受的年齡!