深度学习一下EventBus的原理
用法
public static class MessageEvent { /* Additional fields if needed */ }
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
//粘性事件
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onMessageEvent(MessageEvent event) {/* Do something */};
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
EventBus.getDefault().post(new MessageEvent());
//增加一个粘性事件,发送粘性事件后,再次订阅一个粘性事件会 立即触发方法
EventBus.getDefault().postSticky(new EventBusMessage("发送给子界面的黏性事件"));
官网给的使用方法,一个类,一个带有 @Subscribe
注解的方法,在start和stop分别注册和取消注册,一个post发送方法 ,我增加了一个粘性事件
从注册开始
EventBus.getDefault().register(this);
1、EventBus.getDefault()
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
//对EventBus() 初始化
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
双重锁,单例 获取 EventBus
对象
2、.register(this);
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
第一部分 findSubscriberMethods(subscriberClass)
//subscriberMethodFinder.findSubscriberMethods(subscriberClass);
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//从缓存中取
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//这里默认false
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 {
//key:subscriberClass 也就是当前的类
//value:订阅的方法
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
这里有个METHOD_CACHE 缓存,key是 Class
,Value是 List<SubscriberMethod>
根据类,缓存这个类里面所有订阅的方法
findUsingInfo(subscriberClass)
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//准备一个findState,这里面的方法是从缓存池中取一个,取不到就new一个
FindState findState = prepareFindState();
//一个状态对象, 根据subscribeClass初始化
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//这里给出一个 订阅者信息
findState.subscriberInfo = getSubscriberInfo(findState);
//如果找到 直接取SubscriberMethod[]
if (findState.subscriberInfo != null) {
SubscriberMethod[] arrayfindState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.methosubscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMeth;
}
}
} else {
//查找订阅的方法
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
//这里面就很简单了
//回收findState,把findState放到 FIND_STATE_POOL[] 状态池中
return getMethodsAndRelease(findState);
}
//给出一个订阅者信息
getSubscriberInfo(findState);
private SubscriberInfo getSubscriberInfo(FindState findState) {
//由于这个findState是缓存获取的,有可能是有信息的,也有可能是有父类信息的
//所以 判断有信息和父类信息
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
//返回父类信息
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
//一样就返回 这个findState可能是子类,也有可能是父类
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
//再从索引的List中去查
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
//查找订阅的方法
findUsingReflectionInSingleClass(findState);
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
//这个是返回所有方法包括private
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
//删除try-catch代码减少代码,这里是用getMethods方法 返回方法,
methods = findState.clazz.getMethods();
}
//循环所有方法去找被标记订阅的方法
for (Method method : methods) {
int modifiers = method.getModifiers();
//只要不是public,并且不是static abstract,否则抛异常
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
//获取所有参数
Class<?>[] parameterTypes = method.getParameterTypes();
//只能是一个参数
if (parameterTypes.length == 1) {
//获取这个方法的注解 @Subscribe
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
//注解存在
if (subscribeAnnotation != null) {
//直接获取第0个参数类型
Class<?> eventType = parameterTypes[0];
//checkAdd 是一个二次检查
if (findState.checkAdd(method, eventType)) {
//给出注解中设置的属性 ThreadMode.MAIN 或者其他
ThreadMode threadMode = subscribeAnnotation.threadMode();
//关键,new SubscriberMethod(..)把@Subscribe方法的信息,做成一个对象,
//这个信息是注解里面设置的属性,主线程还是子线程或者是粘性事件等等
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");
}
}
}
到这里已经完成注册里的第一部分
这一部分主要就是把订阅的方法,类作为key,类里面订阅的方法作为value放入METHOD_CACHE缓存中
用了FindState做信息处理
第二部分 for里面的subscribe(subscriber, subscriberMethod);
这一段还不太好 先说,因为这一段是处理粘性事件的
到这里以上已经完成了注册过程
EventBus.getDefault().post(new MessageEventOne());
EventBus.getDefault().post(new MessageEventOne());
public void post(Object event) {
//获取一个ThreadLocal对象
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
//默认是post
if (!postingState.isPosting) {
//isMainThread(),里面注释说了 检查当前线程是否在主线程中运行
//如果不是在Android上 一直返回true
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
//队列不空
while (!eventQueue.isEmpty()) {
//队列 remove 移除 并且返回这个对象
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
postSingleEvent(eventQueue.remove(0), postingState);
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
//是否有继承关系 默认是true
if (eventInheritance) {
//获取eventClass对象的所有接口、 父类 以及父类接口
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
//正真是在这里post的
//这里是逻辑或运算
//只有两个都是 false的时候 结果才是false
//subscriptionFound 初始为false 结果看后面的
//正常这里执行完成肯定返回true
//逻辑或运算,假设要循环判断4个内容,并且把4个内容都要走完,只要有一个内容完成了就返回true
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));
}
}
}
//获取eventClass对象的所有接口、 父类 以及父类接口
lookupAllEventTypes(Class<?> eventClass)
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();
}
//用map保存
//key是当前对象,value是List,所有接口、父类和父类接口
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}
postSingleEventForEventType(event, postingState, clazz)
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
//同步取对象
//这是当前已经注册的所有订阅方法是个map,是根据类来区分的
//key是 Class类对象
//value是CopyOnWriteArrayList<Subscription>
//Subscription是订阅的方法,包括方法名、订阅的类、是否存活
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
//判空
if (subscriptions != null && !subscriptions.isEmpty()) {
//循环这写方法, 如果是多个方法,那肯定是方法名不同,接受的参数一样
for (Subscription subscription : subscriptions) {
//赋值参数
postingState.event = event;
//赋值方法信息
postingState.subscription = subscription;
boolean aborted;
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;
}
//post数据
postToSubscription(subscription, event, postingState.isMainThread);
//代码太长 删除部分
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
//删除 POSTING:
case MAIN:
if (isMainThread) {
//主线程直接执行
//这里面就是 method.invoke 反射执行方法了
invokeSubscriber(subscription, event);
} else {
//这个mainThreadPoster里面非常复杂
//这个对象由mainThreadSupport创建
//又new HandlerPoster
//这个HandlerPoster是继承Handler的 ,里面自己维护了一个队列
//最后是通过handleMessage() 里面调用invoke反射
mainThreadPoster.enqueue(subscription, event);
}
break;
//删除 MAIN_ORDERED:
//删除 BACKGROUND:
//删除 ASYNC:
}
}
post也就是根据post出去的对象去,在 subscriptionsByEventType
对象里找,找到了就反射执行方法。
这里为什么需要ThreadLocal,我觉得这里post()存在高并发的情况,比如十几个线程同时post(),并且需要数据隔离开。
粘性事件
EventBus.getDefault().postSticky(new MessageEventOne());
发送粘性事件
public void postSticky(Object event) {
synchronized (stickyEvents) {
//同步用map收集起来
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
//先不看注释,这个post有意思又回到前面 发射了一次
//也就是说粘性事件比普通post事件多了一件事情,把对象放到了stickyEvents中
//也就是说,你发送一个粘性事件,这个里面的对象,在之前类中已经订阅过了,也会当作普通post发送一遍
post(event);
}
这里 粘性事件要注意一下
回到第二部分 怎么执行粘性事件
第二部分 for里面的subscribe(subscriber, subscriberMethod);
这段代码是在 查找当前类里所有的订阅方法之后才做的事情
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//获取当前类 订阅方法之后 进行订阅操作
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//遍历取 当前的事件
subscribe(subscriber, subscriberMethod);
}
}
}
//其中的一个方法
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
//这是最后要发送这里的东西
//第一个参数 理解为 发那个类,肯定是当前类
//第二个参数是 之前循环的一个方法
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//subscriptionsByEventType 这是个map
//key:是所有发射的类型 比如:bean1
//value:是方法,是根据类型来的,这里就是所有订阅的方法参数的bean1
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);
}
}
//这里for循环的代码像是处理优先级
//但是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;
}
}
//typesBySubscriber 这也是个map
//根据 类Class 来存方法List的
//可以根据 类Class 里面 有哪些订阅的方法
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
//判空初始化
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
//根据上面初始化 ,添加当前的方法
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {
//默认true 向上查找父类
if (eventInheritance) {
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);
}
}
}
粘性事件 是在注册的时候处理的,遍历 stickyEvents
,找出所有 与当前传进来的方法的参数一致的进行反射(同事包括父类)
大致整理一下重要的对象
SubscriberMethodFinder
SubscriberMethodFinder subscriberMethodFinder;
是 寻找订阅者方法 的一个类
这个类里面
-
Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
这个METHOD_CACHE
是个map 缓存着所有订阅的类,value是这些类里面的方法,便于解除订阅的类,又重新订阅,可以直接获取到方法 -
FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
这个FIND_STATE_POOL循环使用FindState,findUsingInfo()
是用来寻找当前类以及父类的订阅方法
FindState(是个内部类)起到一个辅助作用,并把找到的方法放到subscriberMethods
中
EventBus
-
Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
这个map是用来记录,key:订阅的参数,value:是所有对应参数的 方法
Subscription
记录是那个类 和方法的相关信息
post发送消息 是根据subscriptionsByEventType
来发送消息的 -
Map<Object, List<Class<?>>> typesBySubscriber;
根据类,索引里面订阅的方法,主要用于解除注册 -
Map<Class<?>, Object> stickyEvents;
发送的粘性事件都会存到这里,用发送的对象作为key存储 -
MainThreadSupport mainThreadSupport;
获取android主线程的,在安卓上才有用,还有几个是针对线程类型来定了类
最后一步
EventBus.getDefault().unregister(this);
EventBus.getDefault().unregister(this);
public synchronized void unregister(Object subscriber) {
//根据当前类,拿到所有可以接受的对象
//比如MainActivity 有5个订阅方法,有5个不同的Bean
//这里就是拿到5个Bean
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
//循环解除注册
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
//这里是真移除,多次解绑同一类 只会打出下面的log
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
//具体解除
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//获取和Bean相关的类信息 是记录在Subscription里面
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);
//找到一样 "类" 用“类”比较好理解 ,把是否存活 改为false
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
解除注册也好理解,也就是根据当前类对象,找这个类中所有订阅的参数Bean,根据这个Bean,去找关联的订阅方法,把存活改为false,最后移除掉
到此EventBus,订阅、解除注册、发送普通事件、发送粘性事件大致分析完了
总结
主要就是subscriptionsByEventType:根据发射的对象来找注册的方法
我以为核心就是这个对象,看了一圈这个库 自己实现也并不难,主要就是根据对象 invoke
注册的方法,当然人家的库也不是一个人一天两天的就写完的,也是经过时间的打磨而成。
学艺不精,如果内容有错误请及时联系我,我及时改正