EventBus源碼理解
EventBus是我們在開發(fā)中經(jīng)常使用的開源庫竹揍,使用起來比較簡單材失,而且源碼看起來不是很吃力痕鳍。受到廣大開發(fā)者的喜愛~
綜述 !
上面這張圖片很好的解釋了EventBus工作流程,簡單來說就是事件被提交到EventBus之后進(jìn)行查找所有訂閱該事件的方法然后執(zhí)行這些方法.
獲取EventBus實(shí)例(單例模式)
使用了雙重判斷的方式龙巨,防止并發(fā)的問題笼呆,還能極大的提高效率。
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null){
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
構(gòu)造方法
public EventBus() {
this(DEFAULT_BUILDER);
}
注冊
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
這里面其中參數(shù)就是訂閱者旨别,也就是我們寫的this诗赌,register方法主要完成兩件事,查找訂閱者中所有的訂閱方法,然后通過遍利訂閱著的訂閱方法完成訂閱操作秸弛。我們首先看下findSubscriberMethods這個(gè)方法:
//從緩存中獲取SubscriberMethod集合
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//ignoreGeneratedIndex是否忽略注解器生成的MyEventBusIndex
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
SubscriberMethod 這個(gè)類中主要是用保存訂閱方法的Method對象铭若,線程模式,事件類型递览,優(yōu)先級叼屠,是否粘性事件等屬性,主要是兩個(gè)方法findUsingReflection(subscriberClass)绞铃,findUsingInfo(subscriberClass)镜雨,這兩個(gè)方法的區(qū)別就是有沒有配置subscriberInfo
findUsingInfo
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//在FindState里面,它保存了一些訂閱者的方法以及對訂閱方法的校驗(yàn)
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
// 如果我們通過EventBusBuilder配置了MyEventBusIndex儿捧,便會獲取到subscriberInfo 通常情況下我們下代碼的時(shí)候并沒有配置~
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//通過反射來查找訂閱方法
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
# findUsingReflectionInSingleClass
- 沒有通過EventBusBuilder配置MyEventBusIndex的情況下就執(zhí)行這個(gè)方法了
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();
//定于方法中只能有一個(gè)參數(shù)
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//保存到findState對象當(dāng)中
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");
}
}
}
回到register這個(gè)方法中荚坞,上面我們分析了尋找訂閱著方法部分,接下來就是注冊了
subscribe
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//獲取訂閱者方法中的訂閱事件
Class<?> eventType = subscriberMethod.eventType;
//創(chuàng)建一個(gè)Subscription來保存訂閱者和訂閱方法
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//獲取當(dāng)前訂閱事件中Subscription的List集合
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
//該事件對應(yīng)的Subscription的List集合不存在菲盾,則重新創(chuàng)建并保存在subscriptionsByEventType中
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//肯定藥判斷訂閱者是否已經(jīng)被注冊啦
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//將newSubscription按照訂閱方法的優(yōu)先級插入到subscriptions中
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);
}
//將當(dāng)前的訂閱事件添加到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è)方法才是真正的注冊颓影,上面我們說的知識尋找訂閱者訂閱事件的方法。概括來說首先會根據(jù)subscriber和subscriberMethod來創(chuàng)建一個(gè)Subscription集合subscriptions懒鉴,然后根據(jù)事件類型eventType獲取事件集合并把他們添加到typesBySubscriber中诡挂,然后把Subscription對象添加到subscriptions中。
事件的發(fā)送
首先藥獲取EventBus對象临谱,然后通過Post方法進(jìn)行事件的發(fā)送
public void post(Object event) {
//PostingThreadState保存著事件隊(duì)列和線程狀態(tài)信息
PostingThreadState postingState = currentPostingThreadState.get();
//獲取事件隊(duì)列咆畏,并將當(dāng)前事插入到事件隊(duì)列中
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
//當(dāng)前線程是否為主線程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;
// 判斷是否取消
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
//處理隊(duì)列中的所有事件
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
上面在訂閱的時(shí)候我們以訂閱事件為key,將Subscription的List集合作為Value保存到了一個(gè)Map中 吴裤,下面這個(gè)方法就是通過key來取出集合
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);
}
}
這就是我們在接收信息的時(shí)候所用到的幾個(gè)方法,具體含義就不再啰嗦了溺健。到這里啊管理EventBus所涉及的源碼分析的差不多了麦牺,雖然還有好多地方?jīng)]有分析到位钮蛛,但大體的思路是有的。