2 事件分发
事件分发一般调用post方法,调用流程图如下,
post方法如下,
public void post(Object event) {
//获取当前线程的postingState
PostingThreadState postingState = currentPostingThreadState.get();
//取得当前线程的事件队列
List<Object> eventQueue = postingState.eventQueue;
//将该事件添加到当前的事件队列中等待分发
eventQueue.add(event);
// 判断是否有事件正在分发
if (!postingState.isPosting) {
//判断是否是在主线程post
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的定义如下,
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,而这段数据是不会与其他线程共享的。
currentPostingThreadState实际是一个包含了PostingThreadState的ThreadLocal对象,这样可以保证取到的都是自己线程
对应的数据。
PostingThreadState是Event的内部类,主要包含一些变量,
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>(); //当前线程的事件队列
boolean isPosting; //是否有事件正在分发
boolean isMainThread; //post的线程是否是主线程
Subscription subscription; //订阅者
Object event; //订阅事件
boolean canceled; //是否取消
}
PostingThreadState中包含了当前线程的事件队列,就是当前线程所有分发的事件都保存在eventQueue事件队列中。
以及订阅者订阅事件等信息,有了这些信息就可以从事件队列中取出事件分发给对应的订阅者。
postSingleEvent方法如下,
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();//得到事件类型
boolean subscriptionFound = false;
if (eventInheritance) { //是否触发订阅了该事件(eventClass)的父类,以及接口的类的响应方法.
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) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
lookupAllEventTypes方法会将事件放入eventTypesCache变量中保存,
private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
synchronized (eventTypesCache) {
List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
if (eventTypes == null) {
eventTypes = new ArrayList<>();
Class<?> clazz = eventClass;
while (clazz != null) {
eventTypes.add(clazz);
addInterfaces(eventTypes, clazz.getInterfaces());
clazz = clazz.getSuperclass();
}
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}
该变量的定义如下,
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
放入eventTypesCache中统一管理,避免不必要的资源浪费。
postSingleEventForEventType方法首先根据根据事件类型获取所有的订阅者,然后向每个订阅者分发事件,
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);
•••
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
//默认的 ThreadMode,表示在执行 Post 操作的线程直接调用订阅者的事件响应方法,
//不论该线程是否为主线程(UI 线程)。
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);
}
}
invokeSubscriber方法如下,
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);
}
}
通过反射调用订阅者的订阅函数 并把event作为参数传入。
小结:
1、首先获取当前线程的PostingThreadState对象从而获取到当前线程的事件队列
2、通过事件类型获取到所有订阅者集合
3、通过反射执行订阅者中的订阅方法