使用篇
1.添加依賴庫(kù)
compile 'org.greenrobot:eventbus:3.0.0'
2.注冊(cè)遂黍、訂閱、取消訂閱事件
EventBus.getDefault().register(obj);//注冊(cè)
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)//sticky:true為黏性事件堂鲜,false為一般事件
public void onMessageReceive(Object obj) {//訂閱
//onMessageReceive這個(gè)方法名可以任意取羹应,obj為發(fā)布者發(fā)布的事件類型
//省略...
}
EventBus.getDefault().unregister(obj);//取消訂閱
3.事件發(fā)布者發(fā)布事件
EventBus.getDefault().post(obj);//一般事件
EventBus.getDefault().postSticky(obj);//黏性事件
4.混淆
-keepattributes *Annotation*
-keepclassmembers class **{
@org.greenrobot.eventbus.Suscribe<methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode{*;}
#only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent{
<init>(java.lang.Throwable);
}
源碼解析篇
當(dāng)我們使用EventBus時(shí)丘逸,首先會(huì)調(diào)用EventBus.getDefault()來獲取EventBus實(shí)例浦徊,下面看getDefault方法:
EventBus#getDefault
static volatile EventBus defaultInstance;//EventBus實(shí)例
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
很明顯馏予,這是采用DCL雙重檢查的單例設(shè)計(jì)模式,下面看它的構(gòu)造方法:
//EventBus的建造者模式builder,通過它為EventBus設(shè)置各種默認(rèn)屬性
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
public EventBus() {
this(DEFAULT_BUILDER);//DEFAULT_BUILDER為EventBus的建造者模式builder
}
EventBus(EventBusBuilder builder) {
//private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
//訂閱者與訂閱事件的集合盔性,注意:一個(gè)訂閱者可以訂閱多個(gè)訂閱事件
//因此是一個(gè)訂閱者和若干個(gè)訂閱事件
subscriptionsByEventType = new HashMap<>();
//private final Map<Object, List<Class<?>>> typesBySubscriber;
//訂閱事件類型霞丧,根據(jù)訂閱對(duì)象輕松找到訂閱者類,用于取消訂閱時(shí)
typesBySubscriber = new HashMap<>();
//private final Map<Class<?>, Object> stickyEvents;
//訂閱者和訂閱事件冕香,黏性事件
stickyEvents = new ConcurrentHashMap<>();
//這是一個(gè)handler,用于排隊(duì)發(fā)布事件與取出發(fā)布事件來消費(fèi)
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
//后臺(tái)線程
backgroundPoster = new BackgroundPoster(this);
//異步線程
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
//private final SubscriberMethodFinder subscriberMethodFinder;
//訂閱者方法的查找類蛹尝,這個(gè)類很重要,用于查找訂閱者的訂閱方法(集合)
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
//省略...
}
通過構(gòu)造方法悉尾,它調(diào)用了this(DEFAULT_BUILDER)突那,這里的DEFAULT_BUILDER就是EventBusBuilder,可以看出构眯,它通過建造者模式對(duì)EventBus進(jìn)行各種配置愕难。這里就不貼EventBusBuilder的代碼了,可自行閱讀EventBusBuilder源碼惫霸。
在獲取了EventBus實(shí)例后猫缭,會(huì)調(diào)用注冊(cè)方法,把訂閱者注冊(cè)到EventBus中壹店。下面看這個(gè)注冊(cè)方法:
EventBus#register
public void register(Object subscriber) {
//獲取訂閱者類class
Class<?> subscriberClass = subscriber.getClass();
//通過訂閱者方法查找類的查找方法猜丹,返回訂閱方法SubscriberMethod集合
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {//遍歷訂閱方法集合
subscribe(subscriber, subscriberMethod);//對(duì)每個(gè)訂閱者進(jìn)行注冊(cè)
}
}
}
通過閱讀register源碼,我們不難看出它整體思路:通過訂閱者class茫打,獲取該訂閱者里面所有的訂閱方法居触,然后開啟同步鎖并遍歷訂閱方法妖混,對(duì)每一個(gè)訂閱方法進(jìn)行注冊(cè)操作老赤。
這里要補(bǔ)充說明一下SubscriberMethod(訂閱方法)里面的幾個(gè)屬性:
public class SubscriberMethod {
final Method method;//訂閱者定義的方法
//ThreadMode為枚舉類型,取值如下:POSTING,MAIN,BACKGROUND,ASYNC
final ThreadMode threadMode;//訂閱方法工作的線程
final Class<?> eventType;//EventBus發(fā)布(post)的事件類型制市,即訂閱方法接收的數(shù)據(jù)類型
final int priority;//訂閱方法優(yōu)先級(jí)
final boolean sticky;//是否為黏性方法
//其余部分省略...
}
下面看看訂閱者方法查找類究竟是如何查找訂閱方法的领追?
SubscriberMethodFinder#findSubscriberMethods
//METHOD_CACHE是緩存雌澄,key是訂閱者,value是訂閱方法集合
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
//是否忽略注解器生成的XxxEventBus
private final boolean ignoreGeneratedIndex;
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//從緩存中獲取訂閱者類class的訂閱方法
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {//一旦在緩存中找到,就不再查找掘托,直接返回訂閱方法集合
return subscriberMethods;
}
//ignoreGeneratedIndex默認(rèn)為false,也可以通過EventBusBuilder來設(shè)置。
//這里因?yàn)槲覀兪峭ㄟ^EventBus.getDefault()方法來獲取的實(shí)例
//所以ignoreGeneratedIndex是默認(rèn)false的情況,即執(zhí)行else情況
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 {
//把訂閱者類class與訂閱方法集合存入緩存肩钠,方便下次調(diào)用不再繼續(xù)查找,直接緩存讀取
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
閱讀上面源碼可知:首先從緩存METHOD_CACHE中查找訂閱方法集合兽间,找到立即返回历葛,后面不會(huì)再執(zhí)行;否則嘀略,根據(jù)ignoreGeneratedIndex是否為true,執(zhí)行查找獲取對(duì)應(yīng)的訂閱方法集合恤溶;接著對(duì)找到的訂閱方法集合判空乓诽,如果是空,則拋出異常咒程,不為空時(shí)鸠天,則把訂閱者與對(duì)應(yīng)的訂閱方法集合存入緩存,方便下次調(diào)用不需重新查找帐姻,最后返回訂閱方法集合稠集。
從上面源碼可知,查找訂閱方法由findUsingInfo方法執(zhí)行卖宠,下面看該方法:
SubscriberMethodFinder#findUsingInfo
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();//返回FindState實(shí)例
findState.initForSubscriber(subscriberClass);//初始化FindState
while (findState.clazz != null) {//當(dāng)findState.clazz == null時(shí)結(jié)束循環(huán)
//獲取訂閱者信息巍杈,并賦值給findState.subscriberInfo
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {//對(duì)findState.subscriberInfo進(jìn)行判空
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);
}
觀察findUsingInfo方法,首先執(zhí)行的是prepareFindState方法扛伍,返回查找狀態(tài)類FindState的實(shí)例筷畦。
這里需補(bǔ)充一下說明FindState,它是SubscriberMethodFinder的靜態(tài)內(nèi)部類:
SubscriberMethodFinder靜態(tài)內(nèi)部類FindState
static class FindState {
//訂閱方法
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
Class<?> clazz;//訂閱者class
boolean skipSuperClasses;//是否跳過檢查父類class
SubscriberInfo subscriberInfo;//訂閱者信息
//其他略...
}
下面看prepareFindState方法是如何返回查找狀態(tài)類FindState實(shí)例的:
SubscriberMethodFinder#prepareFindState
private static final int POOL_SIZE = 4;
//定義一個(gè)容量為4的查找狀態(tài)數(shù)組
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {//以數(shù)組作為同步鎖
for (int i = 0; i < POOL_SIZE; i++) {//對(duì)數(shù)組進(jìn)行遍歷
FindState state = FIND_STATE_POOL[i];
if (state != null) {//一旦發(fā)現(xiàn)查找狀態(tài)不為空刺洒,立即返回鳖宾,并把數(shù)組內(nèi)查找狀態(tài)置為空
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();//在數(shù)組內(nèi)的查找狀態(tài)均為空時(shí),新建一個(gè)查找狀態(tài)實(shí)例返回
}
在獲得FindState實(shí)例后逆航,調(diào)用initForSubscriber初始化該狀態(tài):
FindState#initForSubscriber
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;//把訂閱者class賦值給subscriberClass和clazz
skipSuperClasses = false;
subscriberInfo = null;
}
之后在findState.clazz不為空的條件下循環(huán)鼎文,直到findState.clazz為空結(jié)束循環(huán),并通過調(diào)用getMethodsAndRelease方法返回List<SubscriberMethod>因俐。
先看循環(huán)體內(nèi)邏輯拇惋,調(diào)用getSubscriberInfo方法,返回查找狀態(tài)的訂閱者信息findState.subscriberInfo抹剩,依據(jù)該信息是否為空撑帖,執(zhí)行相應(yīng)的操作。還是看看getSubscriberInfo方法:
SubscriberMethodFinder#getSubscriberInfo
private List<SubscriberInfoIndex> subscriberInfoIndexes;
private SubscriberInfo getSubscriberInfo(FindState findState) {
//通過FindState#initForSubscriber方法 => subscriberInfo = null可知澳眷,不會(huì)執(zhí)行if語句塊
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
//subscriberInfoIndexes到目前為止胡嘿,均未被賦值,因此也是null钳踊,因此也不會(huì)執(zhí)行if語句塊
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;//有上面可知衷敌,最終執(zhí)行返回null
}
該方法,首先是判空:在傳入的查找狀態(tài)findState中存儲(chǔ)的訂閱信息不為空且其父類定閱信息不為空的條件下拓瞪,獲取其父類訂閱信息superclassInfo缴罗,然后在傳入的訂閱信息與其父類訂閱信息一致的情況下,返回該父類訂閱信息祭埂;第二次判空:當(dāng)subscriberInfoIndexes不為空時(shí)面氓,對(duì)數(shù)組subscriberInfoIndexes進(jìn)行遍歷,在訂閱者信息不為空時(shí)返回,不在往下執(zhí)行侧但;在兩次判空均為null時(shí)矢空,直接返回null(訂閱者信息)。
對(duì)于getSubscriberInfo方法禀横,首先傳入的findState就是上面通過初始化之后的狀態(tài)屁药,即findState.subscriberInfo為空,接著由EventBus的構(gòu)造方法subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex)可知柏锄,subscriberInfoIndexes也是空酿箭,所以最終返回的訂閱者信息是空,所以findUsingInfo方法的循環(huán)體里面的判斷語句執(zhí)行else語句:findUsingReflectionInSingleClass(findState)趾娃。
SubscriberMethodFinder#findUsingReflectionInSingleClass
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
//通過反射獲取訂閱者所有方法(public + private)
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
//通過反射獲取訂閱者所有方法(public)
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {//遍歷所有的方法
int modifiers = method.getModifiers();//獲取方法的修飾符
//只有方法修飾符是public且不是abstract或static才能進(jìn)入執(zhí)行if語句塊
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
//獲取方法的參數(shù)類型數(shù)組
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {//只有當(dāng)方法的參數(shù)為一個(gè)時(shí)缭嫡,才能執(zhí)行if語句塊
//滿足上面所有條件的方法獲取方法注解@Subscribe
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {//當(dāng)獲取的注解不是空時(shí),此方法才是訂閱者類的訂閱方法
//獲取方法參數(shù)類型抬闷,即post(Object event)的event類型
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {//當(dāng)訂閱者與訂閱方添加成功后
ThreadMode threadMode = subscribeAnnotation.threadMode();
//把訂閱方法添加到findState.subscriberMethods里面
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
//默認(rèn)情況下strictMethodVerification=false妇蛀,因此if語句塊不會(huì)執(zhí)行。
} 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);
}
//默認(rèn)情況下strictMethodVerification=false笤成,因此if語句塊不會(huì)執(zhí)行评架。
} 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");
}
}
}
通過閱讀findUsingReflectionInSingleClass源碼,我們知道:首先通過反射獲取訂閱者類的所有方法炕泳,然后對(duì)方法進(jìn)行遍歷纵诞,只有當(dāng)方法修飾符為public、方法參數(shù)只有一個(gè)且該方法存在@Subscribe注解時(shí)培遵,該方法才是訂閱者類的訂閱方法浙芙,接著獲取@Subscribe注解實(shí)例(不為空時(shí)),把訂閱方法(包括方法籽腕,訂閱者嗡呼,線程模式,優(yōu)先級(jí)节仿,是否黏性事件)添加到findState.subscriberMethods里面晤锥。
分析完findUsingReflectionInSingleClass源碼掉蔬,接著就是findState.moveToSuperclass:
FindState#moveToSuperclass
void moveToSuperclass() {
if (skipSuperClasses) {//跳過父類方法檢測(cè)
clazz = null;
} else {//檢測(cè)父類方法時(shí)
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
從這段源碼可知:當(dāng)skipSuperClasses為true廊宪,或者父類方法是系統(tǒng)方法時(shí),置clazz為null女轿,其他時(shí)候置clazz為clazz.getSuperclass()箭启。
最后就是跳出循環(huán)體,通過調(diào)用getMethodsAndRelease方法蛉迹,返回訂閱方法集合了傅寡。
SubscriberMethodFinder#getMethodsAndRelease
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}
這一段源碼很簡(jiǎn)單,就是通過findState.subscriberMethods新建一個(gè)訂閱者方法集合并最終返回,接著重置findState荐操,并把之前的findState設(shè)置到FIND_STATE_POOL數(shù)組中芜抒。
分析完查找訂閱者的訂閱方法之后,回到EventBus的register方法托启,采用同步鎖并遍歷訂閱方法集合宅倒,對(duì)找到的每一個(gè)訂閱方法與訂閱者進(jìn)行注冊(cè)操作。
EventBus#subscribe
// Must be called in synchronized block必須在同步代碼塊中調(diào)用
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//首先獲取EventBus的post數(shù)據(jù)類型
Class<?> eventType = subscriberMethod.eventType;
//創(chuàng)建一個(gè)訂閱事件(包括訂閱者和訂閱方法)
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
//以發(fā)布的數(shù)據(jù)類型為key屯耸,獲取線程安全的發(fā)布事件集合
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {//當(dāng)集合為空時(shí)拐迁,new一個(gè),并把發(fā)布數(shù)據(jù)類型與發(fā)布事件存入緩存
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {//當(dāng)集合不為空疗绣,且集合內(nèi)包含該發(fā)布事件线召,則拋異常。
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//這部分代碼是把訂閱事件按優(yōu)先級(jí)插入集合或集合末尾插入
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
//當(dāng)?shù)竭_(dá)集合末尾或此發(fā)布事件的優(yōu)先級(jí)高于前一個(gè)多矮,則在末尾或該一事件前插入缓淹,之后跳出循環(huán)
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
//Map<Object, List<Class<?>>> typesBySubscriber
//從緩存中根據(jù)key(訂閱者)取出value(發(fā)布事件類型)
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {//如果集合為空,創(chuàng)建一個(gè)
subscribedEvents = new ArrayList<>();
//把訂閱者與發(fā)布的訂閱事件集合存入緩存
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);//把發(fā)布的訂閱事件存入集合
if (subscriberMethod.sticky) {//根據(jù)是否黏性事件
if (eventInheritance) {//默認(rèn)是true塔逃,事件是否有繼承性
// 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 {
//Map<Class<?>, Object> stickyEvents
//緩存中根據(jù)發(fā)布的事件類型class,取出原發(fā)布事件
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
剖析該方法前割卖,先補(bǔ)充說明一下訂閱事件Subscription這個(gè)類:
final class Subscription {
final Object subscriber;//訂閱者類
final SubscriberMethod subscriberMethod;//訂閱方法(方法,線程患雏,發(fā)布事件類型鹏溯,優(yōu)先級(jí),黏性等)
//一旦EventBus#unregister被調(diào)用淹仑,active就會(huì)變成false丙挽,
//這將通過隊(duì)列事件傳遞EventBus#invokeSubscriber來檢查,以防止競(jìng)態(tài)條件匀借。
volatile boolean active;
}
了解完訂閱事件Subscription后颜阐,再閱讀subscribe方法源碼:首先是根據(jù)訂閱方法,獲取發(fā)布數(shù)據(jù)類型class吓肋,接著創(chuàng)建訂閱事件凳怨,根據(jù)訂閱事件集合是否為空,空則創(chuàng)建集合是鬼,并把發(fā)布數(shù)據(jù)class與訂閱事件集合存入緩存肤舞;不為空則拋重復(fù)注冊(cè)異常;接著根據(jù)訂閱事件的優(yōu)先級(jí)或是否到達(dá)末尾均蜜,把訂閱事件插入適當(dāng)?shù)奈恢美钇剩蝗缓蟾鶕?jù)發(fā)布數(shù)據(jù)class集合是否為空,空則創(chuàng)建囤耳,并把訂閱者與發(fā)布事件集合存入緩存篙顺,不為空時(shí)偶芍,把發(fā)布的事件存入發(fā)布事件集合。最后根據(jù)是否為黏性事件完成事件注冊(cè)德玫。
下面看checkPostStickyEventToSubscription方法:
EventBus#checkPostStickyEventToSubscription
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {//stickyEvent必不為空
postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
}
}
//根據(jù)訂閱事件的線程模式執(zhí)行不同的方法匪蟀,第三個(gè)參數(shù)是判斷是否為主線程
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING://在哪個(gè)線程post就在哪個(gè)線程接收事件并處理
invokeSubscriber(subscription, event);//反射調(diào)用method方法
break;
case MAIN://僅在主線程接收處理
if (isMainThread) {
invokeSubscriber(subscription, event);//反射調(diào)用method方法
} else {
mainThreadPoster.enqueue(subscription, event);//handler處理
}
break;
case BACKGROUND://僅在后臺(tái)程接收處理
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);//線程池處理
} else {
invokeSubscriber(subscription, event);//反射調(diào)用method方法
}
break;
case ASYNC://另啟線程(workthread)接收處理
asyncPoster.enqueue(subscription, event);//線程池處理
break;
default://不屬于以上線程,直接拋未知線程異常
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
至此宰僧,EventBus的register方法分析完畢,下面看post方法:
EventBus#post
public void post(Object event) {
//獲取發(fā)送線程的實(shí)例postingState
PostingThreadState postingState = currentPostingThreadState.get();
//獲取派送事件隊(duì)列,并把事件加入隊(duì)列
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {//事件未派送狀態(tài)
//判斷是否UI線程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;//事件派送狀態(tài)標(biāo)志位置為true
if (postingState.canceled) {//正在派送狀態(tài),如果被取消,拋內(nèi)部異常
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
//當(dāng)派送事件隊(duì)列不為空時(shí),對(duì)第一個(gè)事件進(jìn)行派送,并移除該事件
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {//最終都會(huì)把是否在派送標(biāo)志位和UI線程標(biāo)志位置為false
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
//ThreadLocal可保證不同線程值多樣性(線程獨(dú)享),這里僅創(chuàng)建了一個(gè)PostingThreadState實(shí)例
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
//字面理解:發(fā)送線程的狀態(tài)
//eventbus備注*For ThreadLocal, much faster to set (and get multiple values)*
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>();//事件隊(duì)列
boolean isPosting;//標(biāo)志位,是否在派送
boolean isMainThread;//標(biāo)志位,是否主線程
Subscription subscription;//訂閱事件處理器:訂閱者+訂閱方法+是否激活標(biāo)志位
Object event;//事件
boolean canceled;//標(biāo)志位,是否被取消
}
post方法很簡(jiǎn)單,大體思路:首先獲取派送事件狀態(tài),然后把要派送的是按放入該派送事件狀態(tài)的事件隊(duì)列中,根據(jù)標(biāo)志位未派送狀態(tài),對(duì)事件隊(duì)列中的事件逐一取出并進(jìn)行派送,并且最終把標(biāo)志位是否被派送和UI線程置為false,下面看postSingleEvent方法是如何進(jìn)行事件派送的:
EventBus#postSingleEvent
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;//默認(rèn)訂閱處理器未發(fā)現(xiàn)處理方法
//默認(rèn)為true,表示訂閱事件具有繼承性,即該事件的父類或與該事件實(shí)現(xiàn)同一接口的訂閱者都會(huì)處理該事件
if (eventInheritance) {
//查找所有可處理該事件相關(guān)類或接口
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {//遍歷所有事件派送到的類
Class<?> clazz = eventTypes.get(h);
//檢查這些可處理事件的類是否有處理對(duì)應(yīng)事件的方法,返回值為boolean類型
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {//未發(fā)現(xiàn)可處理該派送事件的類(即沒有訂閱者)
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
//查找所有事件類
private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
//private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
synchronized (eventTypesCache) {//同步鎖
List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
if (eventTypes == null) {
eventTypes = new ArrayList<>();
Class<?> clazz = eventClass;
//直到clazz為空跳出循環(huán)
while (clazz != null) {//查找派送事件的所有父類以及實(shí)現(xiàn)同一接口的類
eventTypes.add(clazz);
addInterfaces(eventTypes, clazz.getInterfaces());
clazz = clazz.getSuperclass();
}
//使用緩存把派送事件類型及其父類或?qū)崿F(xiàn)同一接口類進(jìn)行緩存
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}
//檢查所有可處理該派送事件的類
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {//根據(jù)相關(guān)List<?>取值subscriptions
subscriptions = subscriptionsByEventType.get(eventClass);
}
//如果訂閱事件處理器不為空,且有值時(shí),進(jìn)行遍歷,否則返回false
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;//標(biāo)志位,未被強(qiáng)制停止
try {
//發(fā)送到訂閱處理
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {//最終釋放派送事件,訂閱時(shí)間處理器以及標(biāo)志位是否被取消
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {//如果被取消,則跳出循環(huán),返回false
break;
}
}
return true;
}
return false;
}
postSingleEvent方法首先根據(jù)發(fā)布的事件event來獲取該發(fā)布事件的class,然后根據(jù)發(fā)布事件具有繼承性,查找所有可消費(fèi)處理該事件的相關(guān)類(訂閱者)來處理該事件,過程中又回到前面已經(jīng)分析過的postToSubscription方法,根據(jù)不同線程,調(diào)用不同方法對(duì)事件進(jìn)行派發(fā).至此,post方法也分析完畢.
EventBus#postSticky
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);
}
補(bǔ)充說明下黏性事件,因?yàn)轲ば允录鋵?shí)也是調(diào)用post方法,只是在post之前先緩存了黏性事件而已.
最后分析一下反注冊(cè)u(píng)nregister方法
EventBus#unregister
public synchronized void unregister(Object subscriber) {
//private final Map<Object, List<Class<?>>> typesBySubscriber;
//從集合中取出該訂閱者所有的訂閱事件
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {//如果訂閱事件集合不為空時(shí)
for (Class<?> eventType : subscribedTypes) {//遍歷,反注冊(cè)
unsubscribeByEventType(subscriber, eventType);
}
//從集合中移除該訂閱者
typesBySubscriber.remove(subscriber);
} else {//為空時(shí)不需要反注冊(cè)
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
//解除訂閱者與訂閱事件之間的關(guān)系
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
//從集合中取出所有關(guān)于該訂閱者的訂閱事件處理器
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {//當(dāng)該處理器不為空時(shí)
int size = subscriptions.size();
for (int i = 0; i < size; i++) {//遍歷
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;//標(biāo)志位置為false
subscriptions.remove(i);//移除訂閱事件處理器
i--;
size--;
}
}
}
}
反注冊(cè)的邏輯也是很簡(jiǎn)單:首先根據(jù)訂閱者從集合中取出該訂閱者的所有訂閱事件,然后在該訂閱事件不為空時(shí),進(jìn)行遍歷,并逐一進(jìn)行解除.
OK,至此,EventBus源碼分析完結(jié)!
T.T~