EventBus項目地址爲https://github.com/greenrobot/EventBus,clone到本地,主要看EventBus
這個類就可以
關於EventBus的使用可以閱讀這篇文章https://blog.csdn.net/Icarus_/article/details/103685194
1、註解定義
EventBus使用註解@Subscribe來標識一個註冊方法,RetentionPolicy.RUNTIME表示是運行時註解,ElementType.METHOD表示可註解方法
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
//線程模型
ThreadMode threadMode() default ThreadMode.POSTING;
//是否是粘性事件
boolean sticky() default false;
//訂閱事件優先級
int priority() default 0;
}
2、EventBus初始化
EventBus發送事件,註冊,反註冊都會調用getDefault方法來完成實例的創建。
使用EventBus.getDefault方法獲取一個EventBus對象,內部使用的是單例模式,會初始化一些重要的成員變量。單例模式的構造函數一般都是private的,而這裏的構造函數是public的,這樣設計的原因是EventBus在我們的程序中不僅僅只有一條總線,還有其他的EventBus總線,訂閱者可以註冊到不同的EventBus上,通過不同的EventBus來發送數據,不同的EventBus發送數據是相互隔離開的,訂閱者只會收到註冊在該線程上的數據。
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
public EventBus() {
this(DEFAULT_BUILDER);
}
看一下EventBus類中定義的一些字段:
DEFAULT_BUILDER
,是一個EventBusBuilder,EventBus是通過構造者模式build這個內部類進行對象創建的。
currentPostingThreadState
,是一個ThreadLocal,可以在指定的線程中存儲數據。
subscriptionsByEventType
,發送event時,通過這個map找到訂閱者。
typesBySubscriber
,當註冊和反註冊事件的時候,操作這個map。
stickyEvents
,維護粘性事件。
indexCount
,生成的索引。
subscriberMethodFinder
,對已經註解的方法的查找器。
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
......
};
private final SubscriberMethodFinder subscriberMethodFinder;
private final int indexCount;
最重要的三個成員變量poster,poster就是負責線程間調度的
private final Poster mainThreadPoster;
private final BackgroundPoster backgroundPoster;
private final AsyncPoster asyncPoster;
在構造方法中初始化
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
1.mainThreadPoster,跟進去看一下他的初始化,發現返回的是HandlerPoster
這個類,發現他是繼承自Handler。handleMessage開啓一個循環,從隊列中獲取數據,然後分發pendingPost,在判斷每次分發的時間是否小於最大值,來繼續下一次循環或者跳出循環。
public class HandlerPoster extends Handler implements Poster {
//用來放即將執行的post的隊列
private final PendingPostQueue queue;
//post事件在HandleMessage存在的最大的時間值
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
//標識handler是否運行起來了
private boolean handlerActive;
......
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
//從隊列中獲取pendingPost,他維護着一個對象複用池
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;
}
}
......
}
2.backgroundPoster,跟進去看一下,它實現的是runnable,同樣的在run方法中循環隊列,發送消息。
final class BackgroundPoster implements Runnable, Poster {
.......
@Override
public void run() {
......
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);
}
......
}
}
3.asyncPoster,跟進去看一下,也是實現runnable,他的run方法只獲取隊列中的一個pendingPost進行分發。
class AsyncPoster implements Runnable, Poster {
.......
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
}
3、EventBus註冊
3.1 register方法
當EventBus對象創建好之後,就可以調用註冊方法register來將某個類註冊到這個EventBus對象上。在register方法中,通過subscriberMethodFinder的findSubscriberMethods方法找到註冊到EventBus的subscriber類中所有的被@Subscribe註解的訂閱事件方法,遍歷找到的方法,調用subscribe方法來保存他們。
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.2 findSubscriberMethods方法
findSubscriberMethods方法會把找到的監聽方法封裝成一個SubscriberMethod對象,一個監聽方法就對應一個SubscriberMethod對象,SubscriberMethod類中包含一些重要信息
public class SubscriberMethod {
final Method method; //訂閱方法
final ThreadMode threadMode; //事件模型
final Class<?> eventType; //事件類型
final int priority; //優先級
final boolean sticky; //是否是粘性事件
/** Used for efficient comparison */
String methodString; //方法字符串
}
findSubscriberMethods方法是如何找到一個類中所有被註解的方法的呢。EventBus會將一個類的訂閱方法的列表緩存起來,如果有緩存,則會直接返回,沒有再通過反射或是編譯時生成的代碼找到訂閱方法列表
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//獲取緩存
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
//有則返回
if (subscriberMethods != null) {
return subscriberMethods;
}
//默認爲false
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;
}
}
3.2.1 findUsingInfo方法
看一下findUsingInfo方法,獲取到findState,得到訂閱者及其有關信息,通過循環來遍歷,每次遍歷完之後都會調用findState方法,依次找尋findState父類。最後getMethodsAndRelease方法返回和釋放資源,內部主要就是清空了FindState裏面的3個集合。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//獲取到findState它裏面存儲訂閱者一些信息
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中
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//如果findState集合爲空
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
//返回和釋放資源
return getMethodsAndRelease(findState);
}
FindState是用來保存找到的註解過的方法以及他們的狀態,看一下他的內部
static class FindState {
//保存所有訂閱方法
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
//事件類型爲key,訂閱方法爲value
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
//訂閱方法爲key,訂閱者的class對象爲value
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
......
}
接着看一下prepareFindState()方法,他是從FIND_STATE_POOL對象池中找到FindState對象的,找到之後,將該位置清空,爲了之後的複用。
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();
}
3.2.2 findUsingReflectionInSingleClass方法
接下來看findUsingReflectionInSingleClass方法,它通過反射獲取到註冊到EventBus類中的所有方法,然後遍歷,過濾掉不符合的方法,保留被@Subscribe註解的方法,封裝成SubscriberMethod對象保存起來。
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
//獲取到註冊到EventBus類中的所有方法
// This is faster than getMethods, especially when subscribers are fat classes like Activities
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
......
}
//遍歷所有方法
for (Method method : methods) {
int modifiers = method.getModifiers();
//如果是public,且是非靜態非抽象方法
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
//是否只有1個參數,因爲eventbus只允許訂閱方法中的訂閱事件是1個
if (parameterTypes.length == 1) {
//獲取Subscribe註解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//創建SubscriberMethod對象保存起來
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
//獲取到線程模式
ThreadMode threadMode = subscribeAnnotation.threadMode();
//將訂閱方法添加到findState中
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
}
......
}
......
}
}
看一下里面的checkAdd方法,他是用來判斷訂閱的方法是否可以添加到訂閱方法集合當中。在EventBus中有一個特點,一個訂閱者包括他所有的父類或子類,不會有多個方法相同的全部去接受同一個事件,但是可能會出現這樣一種情況:子類去訂閱該事件,同時父類也會去訂閱該事件,這時通過方法簽名進行檢查
boolean checkAdd(Method method, Class<?> eventType) {
//2級檢查:1級,僅具有事件類型的(快速)。2級具有完整簽名的。
//通常訂閱者沒有監聽相同事件類型的方法。
//使用在FindState中定義的map,返回之前的value也就是之前的方法
Object existing = anyMethodByEventType.put(eventType, method);
//根據之前的方法是否爲空進行下面的操作
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
//根據方法簽名進行檢查
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
3.3 Subscribe方法
findSubscriberMethods方法返回列表List後,在register方法中會遍歷這個列表,調用subscribe方法保存起來,在subscribe方法中,首先會創建一個訂閱方法SubscriberMethod對應的Subscription對象,然後獲取訂閱事件對應的Subscription集合,CopyOnWriteArrayList,如果沒有則創建,最後將新建的Subscription對象存入集合,這個集合又保存在EventBus最重要的數據結構Map<Class<?>, CopyOnWriteArrayList>對象subscriptionsByEventType中,EventBus的註冊主要是完成subscriptionsByEventType對象數據的初始化,這個Map的key爲事件類型的Class對象,value爲Subscription集合。我們在EventBus中所訂閱的事件都會有與之對應的訂閱列表,而列表中每個Subscription都會對應一個訂閱方法。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//獲取訂閱方法對應的事件
Class<?> eventType = subscriberMethod.eventType;
//一個訂閱方法subscriberMethod對應一個Subscription
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//獲取事件對應的Subscription集合
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
//如果沒有集合則創建,並加入subscriptionsByEventType中
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
//如果newSubscription保存過則拋異常
}
}
//獲取CopyOnWriteArrayList<Subscription>集合的大小
int size = subscriptions.size();
//遍歷subscriptions
for (int i = 0; i <= size; i++) {
//根據優先級將新建的newSubscription加入集合
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);
}
}
}
總結一下subscribe
1.首先判斷是否註冊過該事件
2.然後按照優先級插入到subscriptionsByEventType的value的list中
3.然後在添加到typesBySubscriber的value的list中
4.發佈事件,checkPostStickyEventToSubscription
4、EventBus發佈事件
由於註冊時構建了一個事件類型對應的Subscription集合,發佈時獲取到該集合然後遍歷,調用裏面的訂閱方法。
看一下post方法,先通過threadLocal獲取到PostingThreadState,他就是發送事件的線程狀態的封裝類,內部有事件隊列集合,是否正在發送事件的標誌位等
public void post(Object event) {
//通過threadLocal獲取到PostingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
//獲取到事件的隊列
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
//是否正在發送事件
if (!postingState.isPosting) {
//通過looper判斷當前是否在主線程
postingState.isMainThread = isMainThread();
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;
}
}
}
post內部調用了postSingleEvent,postSingleEvent內部又調用了postSingleEventForEventType方法,他會獲取到發佈事件對應的Subscription集合,遍歷,調用postToSubscription方法來完成訂閱方法的調用。
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//獲取到發佈事件對應的Subscription集合
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
//發佈事件,調用Subscription對象對應的訂閱方法
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
}
......
}
return true;
}
return false;
}
postToSubscription裏面會根據訂閱方法的線程模型來完成在哪個線程執行
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
//posting,直接在當前線程執行
invokeSubscriber(subscription, event);
break;
case MAIN:
//mian,在主線程執行
if (isMainThread) {
//如果在主線程,直接執行
invokeSubscriber(subscription, event);
} else {
//否則切換到主線程,內部是handler完成的
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
//將在主線程中調用。該事件總是排隊等待以後交付給訂閱者,因此對post的調用將立即返回。這爲事件處理提供了更嚴格且更一致的順序
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
//如果當前是主線程,則在EventBus內部線程池中執行
backgroundPoster.enqueue(subscription, event);
} else {
//不在主線程直接調用
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
//在EventBus內部線程池中執行
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
5、EventBus的反註冊
註冊是給Map<Class<?>, CopyOnWriteArrayList>對象subscriptionsByEventType中添加Subscription集合,那麼反註冊就是清除掉訂閱者subscriber的Subscription
public synchronized void unregister(Object subscriber) {
//獲取訂閱者訂閱事件類型的集合
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
//遍歷
for (Class<?> eventType : subscribedTypes) {
//通過事件類型和訂閱者找到對應的Subscription並清除
unsubscribeByEventType(subscriber, eventType);
}
//移除訂閱者
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
typesBySubscriber是Map<Object, List<Class<?>>>類型的集合,key是訂閱者,value是訂閱者訂閱事件類型集合。他的數據添加是在註冊時完成的,反註冊時通過他獲取訂閱者訂閱事件類型集合,然後遍歷集合,調用unsubscribeByEventType。
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--;
}
}
}
}
6、EventBus3.0的索引
6.1、索引的創建
EventBus有一個註解處理器模塊EventBusAnnotationProcessor
,此模塊下只有一個類EventBusAnnotationProcessor
@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe")
@SupportedOptions(value = {"eventBusIndex", "verbose"})
public class EventBusAnnotationProcessor extends AbstractProcessor {
......
}
@SupportedAnnotationType指定處理的註解爲@Subscribe,@SupportedOptions指定處理註解的參數,eventBusIndex和verbose,這兩個參數是在build.gradle配置的(配置見eventBus的使用)。
eventBusIndex指定將要生成的EventBus的索引類,verbose是布爾值,編譯時是否打印log。註解處理器的配置文件在模塊下的META-INF/services/javax.annotation.processing.Processor
裏,內容爲
org.greenrobot.eventbus.annotationprocessor.EventBusAnnotationProcessor
接下來看EventBusAnnotationProcessor
的process方法是如何處理註解來生成索引文件的
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
//信使,用來編譯時打印log
Messager messager = processingEnv.getMessager();
try {
//獲取參數eventBusIndex
String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX);
......
//獲取參數verbose
verbose = Boolean.parseBoolean(processingEnv.getOptions().get(OPTION_VERBOSE));
int lastPeriod = index.lastIndexOf('.');
//獲取生成索引文件的包名
String indexPackage = lastPeriod != -1 ? index.substring(0, lastPeriod) : null;
......
//收集所有訂閱者信息
collectSubscribers(annotations, env, messager);
//檢查訂閱者,如果不是public的類裏面或者裏面的事件也不是public則忽略
checkForSubscribersToSkip(messager, indexPackage);
if (!methodsByClass.isEmpty()) {
//創建索引文件
createInfoIndexFile(index);
} else {
......
}
writerRoundDone = true;
}
......
return true;
}
在process方法中,先獲取eventBusIndex和verbose參數,然後調用collectSubscribers方法收集所有訂閱者信息,檢查訂閱者,如果不是public的類裏面或者裏面的事件也不是public則忽略,最後調用createInfoIndexFile生成索引文件。
collectSubscribers收集收集所有訂閱者和他內部所有的訂閱方法,然後保存在一個ListMap集合methodsByClass中,由於EventBusAnnotationProcessor只處理@Subscribe註解,所以collectSubscribers第一個參數annotations集合中只有一個@Subscribe對應的TypeElement
private void collectSubscribers(Set<? extends TypeElement> annotations, RoundEnvironment env, Messager messager) {
//遍歷所有註解類型元素,這裏只有註解@Subscribe對應的類型元素
for (TypeElement annotation : annotations) {
//獲取所有被@Subscribe註解的元素,也就是訂閱方法對應的元素
Set<? extends Element> elements = env.getElementsAnnotatedWith(annotation);
//遍歷所有方法對應的elements
for (Element element : elements) {
if (element instanceof ExecutableElement) {
ExecutableElement method = (ExecutableElement) element;
if (checkHasNoErrors(method, messager)) {
//獲取訂閱方法外部元素,就是所在類的元素類型,如MainActivity
TypeElement classElement = (TypeElement) method.getEnclosingElement();
methodsByClass.putElement(classElement, method);
}
} else {
messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid for methods", element);
}
}
}
}
通過collectSubscribers收集到所有的訂閱者信息後,就調用createInfoIndexFile創建索引類,使用的是JDK的JavaFileObject來生成Java文件。
6.2、索引的使用
生成索引文件後,就可以使用這個索引文件初始化EventBus實例,因爲所有的訂閱方法都在索引文件保存起來了,就不需要通過遍歷和反射註解來解析訂閱方法了。
EventBusBuilder方法創建一個EventBusBuilder對象,然後通過addIndex方法將生成的的索引類加入集合,最後調用InstallDefaultEventBus方法創建EventBus對象。在構造方法中使用subscriberInfoIndexes初始化SubscriberMethodFinder對象。
接下來在註冊過程中使用SubscriberMethodFinder查找訂閱方法時,會直接使用索引類獲取訂閱方法。
EventBus(EventBusBuilder builder) {
......
//使用subscriberInfoIndexes初始化subscriberMethodFinder
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
......
}
默認使用findUsingInfo方法查找所有的訂閱方法,會調用getSubscriberInfo()通過查找索引文件的方式來獲取訂閱者所對應的訂閱者信息SubscriberInfo對象,如果沒有開啓索引加上,則會退化爲反射查找。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//準備一個查找狀態的對象,用來跟蹤訂閱方法查找的過程
FindState findState = prepareFindState();
//設置findState的訂閱者類
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//通過索引獲取subscriberInfo,該對象中包含所有的訂閱方法
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);
}
看getSubscriberInfo()方法
private SubscriberInfo getSubscriberInfo(FindState findState) {
......
if (subscriberInfoIndexes != null) {
//遍歷所有索引文件
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
//獲取訂閱者信息
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
然後就可以通過這個訂閱者信息對象獲取其中的SubscriberMethod數組,完成訂閱方法的查找
@Override
public synchronized SubscriberMethod[] getSubscriberMethods() {
int length = methodInfos.length;
SubscriberMethod[] methods = new SubscriberMethod[length];
for (int i = 0; i < length; i++) {
SubscriberMethodInfo info = methodInfos[i];
methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode,
info.priority, info.sticky);
}
return methods;
}