使用 EventBus 时注意
-
使用 EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();才是开启注解方式 eventBus.register(this);
-
而使用 EventBus.getDefault().register() 是使用反射的方式
** 编译时 主要生成MyIndexEvent类 **
/** 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>();
putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.TestEventBusActivity.class, true,
new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onPostTest", org.greenrobot.eventbusperf.testsubject.MEvent.class,
ThreadMode.MAIN),
}));
putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.PerfTestEventBus.SubscriberClassEventBusAsync.class,
true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEventAsync", TestEvent.class, ThreadMode.ASYNC),
}));
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;
}
}
}
Step1:EventBus .getDefault() 创建了一个单例,采用双校验方式 Step2: 调用EventBus构造方法创建4个集合,集合的命令通过 dataByKey的形式
//以事件类型作为Key,Subscription的List集合作为Value的Map集合,后面post一个事件也就用到这个集合
1. Map<Class<?>,CopyOnWriteArrayList<Subscription>> subscriptionsByEventType = new HashMap<>();
//订阅者作为Key,订阅事件作为Value的Map集合
2 Map<Object, List<Class<?>>> typesBySubscriber = new HashMap<>();
3.Map<Class<?>, Object> stickyEvents== new ConcurrentHashMap<>();
4.Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
4.创建EventBusBuilder :
5.创建一个BackgroundPoster:
创建一个 HandlerPoster extends Handler implements Poster
EventBusBuilder构建构造方法中 创建三个集合
1.创建一个线程池 ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
2.List<Class<?>> skipMethodVerificationForClasses;
3.List<SubscriberInfoIndex> subscriberInfoIndexes;
MainThreadSupport mainThreadSupport;
对于register中的参数,就是我们的订阅者,也就是我们经常传入的this对象。在这个方法中主要完成了两件事情。首先通过findSubscriberMethods方法来查找订阅者中所有的订阅方法。然后遍历订阅者的订阅方法来完成订阅者的订阅操作。
首先在这里来看一下findSubscriberMethods这个方法是如何查找订阅者的订阅方法。在这先描述一下SubscriberMethod类。对于SubscriberMethod类中,主要就是用保存订阅方法的Method对象,线程模式,事件类型,优先级,是否粘性事件等属性。下面就来看一下findSubscriberMethods方法。
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//从缓存中获取SubscriberMethod集合
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//ignoreGeneratedIndex是否忽略注解器生成的MyEventBusIndex
if (ignoreGeneratedIndex) {
//通过反射获取subscriberMethods
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//通过注解器生成的MyEventBusIndex信息获取subscriberMethods,
//如果没有配置MyEventBusIndex,依然通过通过反射获取subscriberMethods
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;
}
}
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//创建和初始化FindState对象
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//获取订阅者信息,没有配置MyEventBusIndex返回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();
}
//回收处理findState,并返回订阅方法的List集合
return getMethodsAndRelease(findState);
}
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//获取订阅方法中的订阅事件
Class<?> eventType = subscriberMethod.eventType;
//创建一个Subscription来保存订阅者和订阅方法
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//获取当前订阅事件中Subscription的List集合
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
//该事件对应的Subscription的List集合不存在,则重新创建并保存在subscriptionsByEventType中
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//判断是订阅者是否已经被注册
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//将newSubscription按照订阅方法的优先级插入到subscriptions中
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中
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);
}
}
}
在这个方法中便是订阅者真正的注册过程。首先会根据subscriber和subscriberMethod来创建一个Subscription对象。之后根据事件类型获取或创建一个Subscription集合subscriptions并添加到typesBySubscriber对象中。最后将刚才创建的Subscription对象添加到subscriptions之中。于是这样就完成了一次订阅者的注册操作
-
通过ThreadLocal获取各自线程的PostingThreadState,所以同一线程使用同一个eventQueue
-
PostingThreadState: 保存正在被邮递的事件
-
将event 添加到PostingThreadState的eventQueue
-
判断是否正在邮递,因为每个线程只有一个PostingThreadState,当前线程只能有一个在处理 开始邮递
-
判断当前线程是否是主线程:postingState.isMainThread
-
通过事件类型查找所有方法 List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
-
postSingleEventForEventType
// 事件类型 查找 订阅者 Subscription CopyOnWriteArrayList subscriptions; synchronized (this) { subscriptions = subscriptionsByEventType.get(eventClass); }
Subscription {
Object 包含订阅者对象subscriber SubscriberMethod 订阅者订阅方法,注解参数
}
-
postToSubscription(Subscription subscription, Object event, boolean isMainThread) 将事件邮递给 邮递给订阅者 isMainThread 参数是判断当前是否是主线程
-
如果是主线程 直接调用 invokeSubscriber(subscription, event) 直接通过反射 调用.invoke传入对象和参数 subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { Log.i("qy","postToSubscription处理线程切换问题"); switch (subscription.subscriberMethod.threadMode) { case POSTING: // 不切换线程,post和订阅者方法在同一个线程执行 invokeSubscriber(subscription, event); break; case MAIN: Log.i("qy","订阅方法需要在主线程"); if (isMainThread) { Log.i("qy","post方法在主线程,直接反射去掉用"); invokeSubscriber(subscription, event); } else { Log.i("qy","post方法在子线程,通过Handler切换到主线程"); mainThreadPoster.enqueue(subscription, event); } break; case MAIN_ORDERED: Log.i("qy","订阅方法需要在主线程排队执行"); if (mainThreadPoster != null) { Log.i("qy","开始排队执行"); mainThreadPoster.enqueue(subscription, event); } else { Log.i("qy","反射立刻执行"); // temporary: technically not correct as poster not decoupled from subscriber invokeSubscriber(subscription, event); } break; case BACKGROUND: Log.i("qy","订阅者需要再 后台执行 BACKGROUND,可以允许排队执行"); if (isMainThread) { Log.i("qy","Post在主线程,所以喜欢转换子线程执行,并且排队执行"); backgroundPoster.enqueue(subscription, event); } else { Log.i("qy","post在子线程,所以可以立即执行"); invokeSubscriber(subscription, event); } break; case ASYNC: Log.i("qy","订阅者需要再 后台执行 不需要排队,直接交给线程池异步执行"); asyncPoster.enqueue(subscription, event); break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); }
}
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
也就是说,unregister 先通过传过来的订阅者找个所有订阅事件类型,比如一个LoginActivity订阅者,里面有很多有参数为 FindEvent LoginEvent 等等,这里也就是先前在订阅的时候保存的集合typesBySubscriber开始派上用场了,接着 通过事件类型 去subscriptionsByEventType 查找所有订阅者,并且判断订阅者等于当前LoginActivity这个,然后remove,同时也要typesBySubscribler 也要remove
CopyOnWriteArrayList 保证多线程安全,提高效率,通过复制,改变引用的方式, 双校验单例模式并使用voliate 阻止重排序问题
BackgroundPoster:后台发布人
private final PendingPostQueue queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
BackgroundPoster implements Runnable, Poster
enqueue 方法:
1. 从pendingPostPool中获取一个PendingPost 对象并赋予新的属性值
2.将PendingPost添加到PendingPostQueue队列,这是一个同步代码块
3.判断一下线程池是否运行,运行就等待,否者就
Poster 发布人 void enqueue(Subscription subscription, Object event);
PendingPost 是一个链表,具有3个属性,事件,订阅者和next,pendingPostPool用来作为PendingPost缓存,也就是
private final static List pendingPostPool = new ArrayList();
Object event; Subscription subscription; PendingPost next;