目录
使用场景:
各组件之间、线程之间的通信,限制比较少。
优势:
1.简化组件间的通信方式;
2.分离事件发布者和订阅者,实现解耦
3.使用简单,库小,运行快
4.可以继承、设置优先级、发送粘性事件
劣势:
1.消息传递是单向的,只能单向广播,无法获得订阅者(subscriber)对事件处理的相关信息;
2.事件只能通过事件类名来区分,当订阅者过多,或者消息种类过多,会比较难维护
源码分析
自认为这张图已经道出了eventBus的精髓,( •̀ ω •́ )y
1.subscriber注册:
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//1.获取当前subscriber所有被@Subscribe注解的方法。
List<SubscriberMethod> subscriberMethods =
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {//2.订阅
subscribe(subscriber, subscriberMethod);
}
}
}
- 调用findSubscriberMethod方法
首先从缓存METHOD_CACHE中获取;
如果没有则会调用findUsingReflection或者findUsingInfo方法。
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//缓存中获取methods,如MainActivity进行了注册操作,
//多次启动MainActivity,就会直接去缓存中拿数据。
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
//反射获取
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//使用subscriber Index生成的SubscriberInfo来获取订阅者的事件处理函数
//(新特性,利用注解获取onEvent方法,更快)
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> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
回到findSubscriberMethods看下一条注释
findUsingInfo方法中遍历注册对象以及其所有父类,调用findUsingReflectionInSingleClass去获取类中符合要求(public,一个参数,@Subscribe)的方法;
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
//一个类对应一个findState
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 {
//获取类中符合要求(public,一个参数,@Subscribe)的方法
findUsingReflectionInSingleClass(findState);
}
//查找父类中的方法
findState.moveToSuperclass();
}
//返回找到的方法
return getMethodsAndRelease(findState);
}
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
//1. 通过订阅者的字节码查找当前类中所有生命的方法
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;
}
// 2. 循环遍历所有的方法
for (Method method : methods) {
//3. 获取方法的修饰符
int modifiers = method.getModifiers();
//4.判断修饰符,订阅方法的修饰符不能是private,static
if ((modifiers & Modifier.PUBLIC) != 0 &&
(modifiers & MODIFIERS_IGNORE) == 0) {
//5. 获取方法的所有的参数
Class<?>[] parameterTypes = method.getParameterTypes();
//6.判断参数的个数,只能有1个参数,订阅方法中
if (parameterTypes.length == 1) {
//7.获取方法上具有subscribe 注解
Subscribe subscribeAnnotation =
method.getAnnotation(Subscribe.class);
//8.含有subscribe注解的方法,就是该类订阅的方法,
//其它不符合的可能就是普通的方法
if (subscribeAnnotation != null) {
//9. 获取第一个参数eventType
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
//10. 获取注解的mode,就是我们在注解上标识的,
//有mainThread,Posting,background,async
ThreadMode threadMode = subscribeAnnotation.threadMode();
//11. 将订阅方法的一系列信息(方法名称,threadMode,优先级,
//是否是粘性等)添加到集合subscriberMethods中去
findState.subscriberMethods.add(
new SubscriberMethod(method,
eventType, threadMode,
subscribeAnnotation.priority(),
subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification &&
method.isAnnotationPresent(Subscribe.class)) {
//12. 参数是多个的时候抛出异常
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)) {
//13. 方法的修饰符不是public的,抛出异常
String methodName = method.getDeclaringClass().getName() + "." +
method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
回到findUsingInfo看下一条注释
最后通过调用getMethodsAndRelease将找到的方法返回
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
//取出findState里面的subscriberMethods
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;
}
}
}
//返回subscriberMethods
return subscriberMethods;
}
回到register看下一条注释;
subscribe:
首先将@Subscribe注解的方法和subscriber封装成一个Subscription 对象,根据其eventType将Subscription存入对应的subscriptions(高优先级在前),即存入subscriptionsByEventType。
对typesBySubscriber 进行添加,这主要是在EventBus的isRegister()方法中去使用的,目的是用来判断这个 Subscriber对象 是否已被注册过。
对于粘性事件的处理,调用checkPostStickyEventToSubscription()方法,最终调用了postToSubscription()这个方法来进行粘性事件的发送。
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//订阅方法的eventType的字节码
Class<?> eventType = subscriberMethod.eventType;
//订阅者和订阅方法封装成一个Subscription 对象
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//从subscriptionsByEventType中根据eventType取得对应的subscriptions
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
//若此event是第一次被注册,则获取到的subscriptions为null,
//此时为此event创建其对应的的subscriptions,将此次封装的subscription添加入subscriptionsByEventType
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);
}
}
//获取所有添加的subscriptions
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
//按照优先级,将此次封装的subscription添加至 subscriptions中(高优先级在前)
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
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);
}
}
}
checkPostStickyEventToSubscription(newSubscription, stickyEvent)最终调用了postToSubscription()这个方法来进行粘性事件的发送
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, Looper.getMainLooper() == Looper.myLooper());
}
}
2.publisher发布:
post方法
/** Posts the given event to the event bus. */
public void post(Object event) {
//在下面给出了PostingThreadState类,可以先看看,然后再来继续看后面的代码
PostingThreadState postingState = currentPostingThreadState.get();
//将event添加入eventQueue。
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()) {
//按照顺序,post一个event, remove一个
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
PostingThreadState:
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}
取出event及其所有父类event,
对于每一个event调用postSingleEventForEventType方法
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
//取出event及其所有父类event
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));
}
}
}
postSingleEventForEventType方法从subscriptionsByEventType中取得该event对应的Subscriptions,逐个post到相应的线程中进行处理,调用postToSubscription方法。
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//获取event对应的subscriptions
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
//post到相应的线程中进行处理
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;
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
//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);
}
}
3.subscriber反注册
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
//在subscribeByEventType中移除此subscriber的所有订阅信息
unsubscribeByEventType(subscriber, eventType);
}
//移除了subscriber和其对应的所有 Event 事件链表
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
unsubscribeByEventType(subscriber, eventType):
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--;
}
}
}
}
补充说明:
- 3.0新特性:订阅者索引代替反射以提升性能及新加@Subscribe注解
源码中在获取method时会进行判断是否采用索引,并且不能使用索引的时候,它会在运行时自动回退到反射模式。
EventBus3.0新特性之Subscriber Index - 简书 - 粘性事件:
项目中有多少Fragment、Activity等载体,事件MyEvent就发送多少份;粘性其意义在于,无论项目中载体类中是否使用EventBus.getDefault().register(this);对EventBus注册过,都会对其发送事件,
● 若载体注册了,则接收处理该粘性事件;
● 若载体未注册,则该粘性事件会缓存起来,
● 一旦载体注册,马上接收处理事件;(源码中在register方法中post达到这个效果)