前兩篇文章講解了使用和register方法谴蔑,本篇文章主要講解post方法以及注解處理器
EventBus源碼解析系列
EventBus源碼解析(一)關(guān)于用法和注解
EventBus源碼解析(二)register與unregister
EventBus源碼解析(三)Post方法和注解處理器
Post方法
從post開始
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;
}
}
}
post里面主要進(jìn)行以下操作
- 從
ThreadLocal
中獲取PostingThreadState项秉,然后把事件Event添加都里面的隊(duì)列中postingState.eventQueue
這里PostingThreadState這個(gè)類為
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}
用來保存一些些狀態(tài)
判斷當(dāng)前事件是否發(fā)送,進(jìn)入到if中,設(shè)置是否是主線程以及posting=true宰译,然后循環(huán)調(diào)用隊(duì)列
postSingleEvent(eventQueue.remove(0), postingState);
不皆,使用完的事件則被移除隊(duì)列最后finally設(shè)置屬性為false
看下這個(gè)事件處理方法
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
//①處理子類
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
//②結(jié)果判斷
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
這里也比較好理解,首先還是這個(gè)eventInheritance
這個(gè)上篇有講過加缘,是來處理含有子類的方法的鸭叙。最終都是調(diào)用postSingleEventForEventType
來處理事件,之后結(jié)果賦值給subscriptionFound
如果沒有找到對(duì)應(yīng)的方法則消費(fèi)一個(gè)默認(rèn)事件NoSubscriberEvent
生百。
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//①根據(jù)事件類型eventType拿到方法集
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
//②保存當(dāng)前狀態(tài)到PostingState
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
//③開始執(zhí)行
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
在這里通過subscriptions = subscriptionsByEventType.get(eventClass);
拿到我們前面register解析到的方法集递雀,之后每進(jìn)行一次處理事件都要設(shè)置下當(dāng)前PostingState
的狀態(tài),而前面也有說到EventBus里面ThreadLocal的泛型是PostingState
蚀浆,這里每次設(shè)置當(dāng)前狀態(tài)主要用來獲取事件的執(zhí)行情況缀程。
之后則調(diào)用postToSubscription
來執(zhí)行事件
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);
}
}
這個(gè)大家也比較熟悉了搜吧,跟前面一篇文章分析一樣,了解ThreadModel的使用后相信你自己也可以分析出來杨凑。
注解處理器
在第二篇文章中我們使用EventBus只是默認(rèn)的使用滤奈,并且最終還是使用反射來獲取類信息,這樣很耗性能撩满,而且在3.0版本之前也是使用反射了蜒程。所以3.0之后多了個(gè)注解處理器的使用,它則是在編譯期將類信息伺帘,通過注解處理器昭躺,自動(dòng)生成索引,大大提高了EventBus的運(yùn)行效率伪嫁。怎么使用呢领炫,我們先看下配置說明。
打開App的build.gradle张咳,在dependencies中添加最新的EventBus依賴:
compile 'org.greenrobot:eventbus:3.0.0'
然后在項(xiàng)目gradle的dependencies中引入apt編譯插件:
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
然后在App的build.gradle中應(yīng)用apt插件帝洪,并設(shè)置apt生成的索引的包名和類名:
apply plugin: 'com.neenbedankt.android-apt'
apt {
arguments {
eventBusIndex "com.yourpackage.MyEventBusIndex" //指定一個(gè)路徑下的,生成的類則是在這里
}
}
接著在App的dependencies中引入EventBusAnnotationProcessor:
apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
配置完成之后脚猾,我們暫且不編譯葱峡,先看下我們的訂閱情況
我在MainActivity.class中使用
@Subscribe(threadMode = ThreadMode.MAIN , sticky = true , priority = 50)
public void receiveEventString(String s){
Log.e(TAG, "receiveEventString: " + s );
}
@Subscribe(threadMode = ThreadMode.BACKGROUND , sticky = false , priority = 100)
public void receiveEventInt(Integer i){
Log.e(TAG, "receiveEventInt: " + i );
}
然后我們選擇編譯Build一下,看看生成的文件
自動(dòng)生成的目錄則是在這里龙助。
我們看下這個(gè)生成類的信息
/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
//關(guān)鍵就是在這里砰奕。把你所有的注冊(cè)信息已經(jīng)在編譯時(shí)期獲取到,并且保存在Map中
putIndex(new SimpleSubscriberInfo(MainActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("receiveEventString", String.class, ThreadMode.MAIN, 50, true),
new SubscriberMethodInfo("receiveEventInt", Integer.class, ThreadMode.BACKGROUND, 100, false),
}));
}
private static void putIndex(SubscriberInfo info) {
SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
}
@Override
public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
if (info != null) {
return info;
} else {
return null;
}
}
}
可以看到在編譯器生成的這個(gè)處理器已經(jīng)獲取到類的所有注解信息封裝到SubscriberInfo
中泌参,然后存放在一個(gè)Map中脆淹,最后調(diào)用getSubscriberInfo
就可以獲取到信息。
MyEventBusIndex
是實(shí)現(xiàn)SubscriberInfoIndex
接口
public interface SubscriberInfoIndex {
SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);
}
好沽一,我們回到上一篇文章獲取類方法那里盖溺。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//①獲取FindState對(duì)象
FindState findState = prepareFindState();
//初始化
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//②獲取訂閱者的信息,一開始為null铣缠,如果有使用注解處理器烘嘱,則不為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 {
//③通過反射來獲取方法信息,之后保存在findState
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
//④從findState中獲取到SubscriberMethod
return getMethodsAndRelease(findState);
}
之前則是在這里第二步②來判斷你有沒有使用注解處理器的蝗蛙。
②通過getSubscriberInfo(findState);
根據(jù)當(dāng)前的findState來獲取訂閱者的信息蝇庭。
private SubscriberInfo getSubscriberInfo(FindState findState) {
...
//判斷有沒有使用注解處理器,如果有使用捡硅,則在編譯器時(shí)候通過讀取@Subscribe()注解并解析保存到subscriberInfoIndexes中了哮内。
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
關(guān)鍵就是這個(gè)subscriberInfoIndexes
判斷,而這個(gè)subscriberInfoIndexes
則在它構(gòu)造方法賦值的
SubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification,
boolean ignoreGeneratedIndex) {
this.subscriberInfoIndexes = subscriberInfoIndexes;
...
}
EventBus(EventBusBuilder builder) {
...
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
...
}
最后則是通過Builder
/** Adds an index generated by EventBus' annotation preprocessor. */
public EventBusBuilder addIndex(SubscriberInfoIndex index) {
if(subscriberInfoIndexes == null) {
subscriberInfoIndexes = new ArrayList<>();
}
subscriberInfoIndexes.add(index);
return this;
}
在Builder這里只是提供了一個(gè)方法來讓你添加,而參數(shù)則是SubscriberInfoIndex
北发,而剛剛我們那個(gè)自動(dòng)生成的處理器則是實(shí)現(xiàn)了這個(gè)接口纹因。
所以只需要這樣設(shè)置便可以使用了
EventBus mEventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
在這里則不能使用getDefalut來創(chuàng)建EventBus了。
EventBus默認(rèn)有一個(gè)單例琳拨,可以通過getDefault()
獲取瞭恰,也可以通過EventBus.builder()
構(gòu)造自定義的EventBus,比如要應(yīng)用我們生成好的索引時(shí)狱庇。
AnnotationProcessor
前面我們說到注解處理器使用的是Apt惊畏,不過很遺憾,Apt作者已經(jīng)不維護(hù)這個(gè)插件了密任,現(xiàn)在則是提倡使用谷歌的AnnotationProcessor
來代替apt颜启。android-apt只支持javac編譯器,而annotationProcessor同時(shí)支持javac和jack編譯器批什。
如何配置呢
dependencies {
...
compile 'org.greenrobot:eventbus:3.0.0'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
只需要在dependencies這里添加annotationProcessor农曲,而不使用apt了。
之后在defaultConfig配置添加
defaultConfig {
...
jackOptions {
enabled true
}
javaCompileOptions {
annotationProcessorOptions {
arguments = [ eventBusIndex : 'org.greenrobot.eventbusperf.MyEventBusIndex' ]
}
}
}
就可以了驻债。
不過這個(gè)AnnotationProcessor
對(duì)版本有要求,確保Android Gradle插件版本是2.2以上形葬,我在測(cè)試的時(shí)候由于沒有去更新這些版本合呐,導(dǎo)致在Build的過程中太久(它去下載對(duì)應(yīng)的版本了),最后才去把所有版本包括AS版本笙以,Gradle淌实,buildToolsVersion全部更新了。
寫到最后也就可以發(fā)現(xiàn)EventBus的設(shè)計(jì)了猖腕。
EventBus采用了觀察者模式設(shè)計(jì)拆祈,通過register(Object)方法來注冊(cè)當(dāng)前類監(jiān)聽,把所有注冊(cè)的類給保存起來倘感,并且通過反射或者注解處理器拿到當(dāng)前類中的監(jiān)聽方法Method放坏,最后在post發(fā)送事件的時(shí)候在內(nèi)部依次搜索每個(gè)注冊(cè)類,然后再根據(jù)post的參數(shù)類型(事件類型)進(jìn)行篩選對(duì)應(yīng)符合參數(shù)類型的方法老玛,然后再根據(jù)ThreadMode設(shè)置的事件處理情況淤年,選擇在哪個(gè)線程中處理調(diào)用反射方法,進(jìn)而接收到事件蜡豹。
而在3.0之前的版本中是使用類似字符串匹配的方法麸粮,比如onEventMainThread這些,之后再使用反射獲取镜廉,而使用反射則是十分損耗性能的弄诲,
所以在3.0之后引入了注解的使用,而注解又引入了注解處理器AnnotationProcessor
娇唯,能夠在編譯期就獲取到所有注冊(cè)類里面對(duì)應(yīng)的注解接收方法齐遵,然后在獲取的時(shí)候就不需要再去反射獲取類的方法寂玲,直接去使用,大大提升了性能洛搀。不過EventBus默認(rèn)是沒有使用注解處理器的敢茁,要自己去設(shè)置使用才有。