一、簡述
EventBus 是安卓中的一個事件總線庫,可用於替代廣播,Handler和用於組件化中組件間通信的庫。
這是EventBus的Github上的一張介紹圖,從圖中可以理解EventBus的工作流程,發佈者即 Publisher 發佈事件到EventBus中,通過EventBus將事件傳遞給觀察者即Suncriber。
二、EventBus的使用
在 module的gradle中添加
implementation 'org.greenrobot:eventbus:3.1.1'
定義一個實體類,作爲傳遞的事件。
public class EventMessageType {
private int type;
private String data;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
3. 事件註冊
在Actiivty的onCreate中調用 EventBus.getDefault().register(this),將該Activity的實例註冊到EventBus中,然後需要爲接收事件的方法添加 @Subscribe註解。在該註解類型中可以設置接收事件所在的線程,優先級,以及是否是粘性事件。當頁面銷燬的時候需要調用 EventBus.getDefault().unregister(this) 解綁註冊。
public class EventBusAct extends AppCompatActivity implements OnClickListener {
private TextView tvDesc;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_event);
tvDesc = findViewById(R.id.tv_desc);
tvDesc.setOnClickListener(this);
EventBus.getDefault().register(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(String msg) {
tvDesc.setText(msg);
}
@Override
protected void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
@Override
public void onClick(View v) {
Intent intent = new Intent();
switch (v.getId()) {
case R.id.tv_desc:
intent.setClass(this, EventBusSecAct.class);
break;
}
startActivity(intent);
}
}
發佈事件通過EventBus發佈一個事件,事件類型可以是基本類型,String類型,或者自定義的JavaBean。
EventBus.getDefault().post("Hello");
使用EventBus就是以上步驟,先註冊事件,然後發佈事件。在註冊事件的地方便能收到發佈事件時攜帶的數據。接下來我們就進入源碼分析。理解EventBus內部是如何工作。
三、源碼分析-註冊流程
3.1 EventBus#getDefault方法
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
EventBus首先通過getDefault方法獲取到單例的EventBus,該方法內做了雙重判斷,由於加了同步鎖會對性能產生影響,這樣做可以優化性能。接下來看EventBus的構造方法。
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
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;
}
在構造方法內,通過EventBusBuilder類初始化了如下數據:
subscriptionsByEventType: Map<Class<?>, CopyOnWriteArrayList>對象。該Map以事件類型的Class對象爲key,以 CopyOnWriteArrayList集合爲value。Subscription保存了Activity實例,以及註解的方法名稱,以及事件類型的Class對象,及註解的值,使用CopyOnWriteArrayList保證了線程安全。
typesBySubscriber: Map<Object, List<Class<?>>>對象。該Map以Activity實例爲key,以事件類型的Class對象爲集合的value,組成映射。
**stickyEvents:**Map<Class<?>, Object>對象。存儲粘性事件的Map。以事件類型的Class對象爲key,以事件類型爲value組成映射。
3.2 EventBus#register方法
調用register方法,在該方法內獲取Activity實例的Class對象,然後調用SubscriberMethodFinder#findSubscriberMethods方法獲取SubscriberMethod方法的集合。然後遍歷調用EventBus#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.3 SubscriberMethodFinder#findSubscriberMethods方法
先從METHOD_CACHE這個map對象緩存中獲取泛型爲SubscriberMethod的集合。不爲空直接返回該對象。不爲空走以下邏輯。
由於ignoreGeneratedIndex初始化時false,因此調用SubscriberMethodFinder#findUsingInfo方法獲取到SubscriberMethod的集合,並添加到METHOD_CACHE緩存中。
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
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;
}
}
METHOD_CACHE
METHOD_CACHE是以Class對象爲key即存儲的是Activity實例的Class對象。以泛型是SubscriberMethod的集合爲value,那麼SubscriberMethod存儲的是什麼值呢。
Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
SubscriberMethod
SubscriberMethod類中存儲了接受事件的方法名稱的反射類型,線程模式,事件類型的Class對象,優先級,是否是粘性事件。
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class<?> eventType;
final int priority;
final boolean sticky;
/** Used for efficient comparison */
String methodString;
....
}
3.4 SubscriberMethodFinder#findUsingInfo方法
先調用SubscriberMethodFinder#prepareFindState方法獲取FindState對象。然後將Activity的實例的Class對象緩存在FindState對象中。由於getSubscriberInfo方法返回爲null,所以最終調用findUsingReflectionInSingleClass方法並將FindState對象傳入。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
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);
}
3.5 FindState#prepareFindState方法
在 prepareFindState 方法中,FIND_STATE_POOL是FindState類型的,大小爲POOL_SIZE=4的長度數組,每次調用時,會找到這個數組內爲空的對象,並將數組內該索引清空,返回當前索引的對象,如果這個數組內爲空重新創建一個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.6 FindState#initForSubscriber
將Actiivty實例的Class對象緩存在FindState內。
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
3.7 SubscriberMethodFinder#findUsingReflectionInSingleClass
在該方法內通過反射獲取Activity的實例的Class對象的所有方法,並獲取方法上的註解值,並最終將方法,運行線程的類型等組裝到SubscriberMethod對象中,並保存在FindState中。
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();
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
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");
}
}
}
3.8 SubscriberMethodFinder#getMethodsAndRelease方法。
將保存在FindState對象中的SubscriberMethod拷貝一份,然後清空FindState內的緩存數據,。
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;
}
3.9 EventBbus#subscribe方法訂閱
將Activity的實例對象和 SubscriberMethod 對象保存在 Subscription 對象中。然後將註解方法的參數的Class對象與Subscription的集合形成映射,保存在 subscriptionsByEventType這個map中。然後按照事件設置的優先級大小對保存在Subscription集合中的信息排序。然後將Activity的實例對象與事件類型的Class對象的集合保存在 typesBySubscriber這個map 中。最後判斷該事件是否是粘性事件。
粘性事件與非粘性事件:指粘性事件可以先發送,後註冊,也會受到發送的信息,非粘性事件是必須先註冊事件,後發送。如果是粘性事件直接調用checkPostStickyEventToSubscription。然後調用postToSubscription這個發送的方法,關於postToSubscription方法稍後再發布分析中去解析。
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);
}
}
}
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
// --> Strange corner case, which we don't take care of here.
postToSubscription(newSubscription, stickyEvent, isMainThread());
}
}
四、源碼分析-發佈流程
4.1 EventBus#post
發佈事件調用的是以下代碼,獲取EventBus的單例並調用post方法。
EventBus.getDefault().post("Hello");
通過currentPostingThreadState這個ThreadLocal對象獲取存儲在內部的PostingThreadState對象。通過PostingThreadState獲取其內部的eventQueue集合。
判斷事件是否在發送,然後判斷是否是主線程,設置到PostingThreadState對象中,循環調用EventBus#postSingleEvent方法,直到eventQueue集合爲空。
/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
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;
}
}
}
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
4.2 PostingThreadState
PostingThreadState是EventBus內部的一個類,存儲Subscription類以及事件類型對象及其他信息。上文提到Subscription中保存了註冊的Actvity的實例對象和存儲了事件類型的Class對象,註解值,及方法名的SubscriberMethod對象。
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}
4.3 EventBus#postSingleEvent
在該方法中首先獲取事件類型的Class對象,接着調用EventBus#postSingleEventForEventType方法。將事件類型對象,以及PostingThreadState和事件類型的Class對象傳進去。
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);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
4.4 EventBus#postSingleEventForEventType
在該方法內通過subscriptionsByEventType這個map獲取到Subscription對象的集合,subscriptionsByEventType這個map在上文的subcribe方法中提到存儲了事件類型的Class對象以及Subscription對象的集合。然後將事件類型對象和Subscription對象設置給PostingThreadState對象。並調用postToSubscription。
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
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;
}
4.5 EventBus#postToSubscription
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 MAIN_ORDERED:
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) {
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);
}
}
ThreadMode:POSTING,默認值,表示發送事件和接受事件在統一線程。在此狀態下調用EventBus#invokeSubscriber方法,在invokeSubscriber方法中通過反射調用保存Subscription對象中Activity實例中的註解方法。
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);
}
}
ThreadMode:MAIN,首先判斷是否是主線程,若是主線程直接調用,此種情況與ThreadMode爲POSTING一致。若不是則調用mainThreadPoster這個Poster#enqueue方法,具體實現是在EventBus初始化時創建Poster的實現類。
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
在MainThreadSupport中的內部類AndroidHandlerMainThreadSupport中通過主線程的Looper對象創建HandlerPoster即是Handler類。
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
最終調用HandlerPoster#enqueue方法,然後調用sendMessage方法,最終調用handleMessage方法,最終調用EventBus#invokeSubscriber方法,在invokeSubscriber方法中通過反射調用Subscription中保存的Activity實例的添加註解的方法。
其他幾種基本類似,就不一一說了,最終調用與其他兩種一致。