事件分发
EventBus3.0的事件的分发时通过EventBus类中的post(粘性事件为postSticky)方法,post与postSticky的唯一区别就是,在postSticky内部首先会向EventBus类中的stickyEvents集合中添加事件类实例,然后在调用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;
}
}
}
在事件分发之前,首先通过currentPostingThreadState内获取PostingThreadState;currentPostingThreadState是一个ThreadLocal<PostingThreadState>,我们知道ThreadLocal在java是保存每个线程中独立的数据,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的;而ThreadLocal存储的PostingThreadState类,就是个信息类;
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>();//事件类队列
boolean isPosting;
boolean isMainThread;//是否是主线程
Subscription subscription;
Object event;//事件类实例
boolean canceled;
}
获取到当前线程的PostingThreadState,并将需要处理的事件类实例添加到PostingThreadState的eventQuenue队列中;如果当前线程的Looper与主线程的Looper一致,这PostingThreadState的isMainThread为true;而PostingThreadState类中的isPosting来判断是否正在进行分发;最后通过postSingleEvent方法循环进行数据的分发处理;
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {//是否触发订阅了该事件的基类以及接口类的相应方法
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);//查找event类所有的基类以及接口
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) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
postSingleEvent方法首先通过lookupAllEventTypes方法查找出所有的event类中所有的基类以及接口;然后对这些循环进行分发;
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;
}
在postSingleEventForEventType方法中我们可以看到我们从EventBus类中subscriptionsByEventType中取出所有匹配的Subscription;并将Subscription实例中的event,subscription赋值给postingState;
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);
}
}
在postToSubscription方法中,subscription.subscriberMethod.threadMode 4种线程模型,当线程模型为POSTING 时,直接执行invokeSubscriber方法,效率也最快;而invokeSubscriber方法也很简单,就是反射中的invoke方法;
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);