一、EventBus的作用
它是一个事件的订阅-发布框架,用来解决组件件通信的问题
值得学习的是使用对象池减少对象的创建,将耗时业务放到编译时期执行的思路
二、EventBus的思路
事件发布前,先准备好订阅者的信息。在发布时候从已经准备好的订阅者信息中取出匹配的订阅者,发布事件。
三、查找订阅方法
查找订阅方法分为两种模式,
第一种是在register的时候通过反射查找所有的订阅方法
第二种是在编译时通过注解解析器,查找到所有的订阅方法
在Register通过反射查找
核心类
1.SubscriberMethodFinder:负责查找类中含有subscribe注解的所有方法
2.FindState:包装类的状态
3.METHOD_CACHE:缓存当前类对应的注解方法
4.findUsingInfo:通过已经准备好的订阅者索引集合查找订阅类
5.findUsingReflectionInSingleClass:解析类的注解,并添加到findstate中
6.SubscriberMethod 封装使用@Subscribe的方法
2.代码流程
1.通过SubscriberMethodFinder对象获取到当前类的所有添加了相应注解的方法
2.完成订阅
register方法
查找监听类中所有使用了subscribe注解的方法,并保存起来。
public void register(Object subscriber) {
//获取当前监听类的类对象
Class<?> subscriberClass = subscriber.getClass();
//找到这个类下所有使用了subscribe标注的方法,并包装成SubscribeMethod集合
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//将这些类
subscribe(subscriber, subscriberMethod);
}
}
}
findSubscriberMethods---findUsingInfo---findUsingReflectionInSingleClass
1.同过SubscribeMethodFinder方法查找出类中所有使用了subscribe注解的方法
/**
* 监听类对象
*
* @param subscriberClass
* @return
*/
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//该类是否之前调用过,如果有从缓存中获取,如果没有 使用find方法查找
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
....
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
.....
return subscribeMethods
}
1.创建FindState类维护这类的状态
2.将这些方法和方法的参数类型,线程类型记录下来,保存成SubscribeMethod对象
2.FindState保存所有这个类下使用了subscribe注解的方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//准备一个FindState,这里运用了享元模式
FindState findState = prepareFindState();
//使用FindState记录下监听类
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//第一次findstateinfo是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();
}
//将这个类缓存起来
return getMethodsAndRelease(findState);
}
/**
* FindState维护的是注册要监听的类
* 这里要查找出这个类中所有使用了
* subscribe注解的方法,保存起来
* * @param findState 类监听方法对象
*/
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
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;
}
//遍历查找类中的每一个方法,所有符合条件的类都加到findstate的subscribes集合中 记录下来
for (Method method : methods) {
//获取方法的修饰符类型
int modifiers = method.getModifiers();
//必须是publish 并且不能是静态的
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) {
//将第一个参数的类型取出来
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
//获取subscribe注解里的threadmode值
ThreadMode threadMode = subscribeAnnotation.threadMode();
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");
}
}
}
subscribe方法的作用是将订阅了所有相同事件的方法通过一个Map(subscriptionsByEventType)维护起来,每个EventType都对应一个SubscribeMethod的集合,这样在发送的时候就可以查找到所有监听了这种事件的方法,将事件全部发送给他们。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//方法的参数类型
Class<?> eventType = subscriberMethod.eventType;
//将方法和注册监听的类关联起来
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
/**
* 将监听方法根据参数类型保存起来,每个参数类型对应一个方法集合
* paramsType--List<Subscription>
* 相同的参数类型,放到一个集合中
* 这样可以在发送事件的时候,将事件发送到所有监听了相同参数类型的方法中
*/
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);
}
}
//将方法按照优先级存入到集合中
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.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);
}
}
}
二、Post方法
获取发送事件的类型,拿到通过register方法保存的监听改事件的所有方法(subscriptionsByEventType集合),并使用反射的方式执行所有维护的方法
1.PostingThreadState 记录当前线程的消息队列的状态,由ThreadLocal维护
2.postSingleEvent 发送消息
不同的线程都维护了一份PostingThreadState对象,负责维护消息的状态
/**
* 每一个线程都单独维护了一个PostingThreadState
* 负责维护当前线程的事件以及事件分发的状态
*/
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>();//消息嘟咧
boolean isPosting;//是否发送
boolean isMainThread;//是否是主线程
Subscription subscription;//订阅的方法
Object event;
boolean canceled;
}
Post方法发送事件
/** Posts the given event to the event bus. */
public void post(Object event) {
//获取当前线程消息队列的状态
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
//添加消息
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
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;
}
}
}
/**
* 发送事件
* @param event 要发送的事件对象
* @param postingState 当前线程的状态
* @throws Error
*/
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
//获取要发送的事件的类型
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
//evenInheritance默认是false
if (eventInheritance) {
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) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
postSingleEventForEventType
获取所有监听该事件的方法,并通过反射执行
/**
* 发送事件
* @param event 事件对象
* @param postingState 消息的线程状态
* @param eventClass 事件的类型
* @return 是否发送成功
*/
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//根据发送事件的对象的类型,从通过register方法记录的保存的集合中subscriptionsByEventType找到所有监听该事件的集合
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;
}
/**
* 使用反射的方式发送数据
* 如果不在对应的线程就使用handler发送到其它线程的looper队列中
* @param subscription 监听类的包装
* @param event 事件对象
* @param isMainThread 是否在主线程
*/
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 MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(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);
}
}
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);
}
}
使用索引信息查找
EventBus提供了编译时生成索引信息的插件,使用方式腾讯bulgy
,它的原理是在编译时,插件执行注解解释器的代码,注解解释器会查找所有使用的subscribe注解的元素,检查他们是否符合标准,然后通过createInfoIndexFile生成订阅方法索引类。
/**
* 设置支持的注解类型
* 避免了只有在调用了register方法的时候才准备订阅者的信息
* https://blog.csdn.net/natural_story/article/details/51444299
* https://www.jianshu.com/p/899063e8452e Element
*/
@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe")
@SupportedOptions(value = {"eventBusIndex", "verbose"})
public class EventBusAnnotationProcessor extends AbstractProcessor {
public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex";
public static final String OPTION_VERBOSE = "verbose";
.....
......
/** Found subscriber methods for a class (without superclasses). */
/**
* 找到所有订阅的方法
*/
private final ListMap<TypeElement, ExecutableElement> methodsByClass = new ListMap<>();
/**
* 运行时注解
* @param annotations
* @param env
* @return
*/
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
//控制台输出的消息
Messager messager = processingEnv.getMessager();
try {
String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX);
......
....
//找到所有符合条件的订阅方法
collectSubscribers(annotations, env, messager);
//校验方法的类是否符合要求
checkForSubscribersToSkip(messager, indexPackage);
if (!methodsByClass.isEmpty()) {
/**
* 为使用了subscribe的类生成一个索引信息,包括方法名,方法参数类型,属于的类
* 包括他们的位置
*/
createInfoIndexFile(index);
} else {
messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found");
}
writerRoundDone = true;
} catch (RuntimeException e) {
// IntelliJ does not handle exceptions nicely, so log and print a message
e.printStackTrace();
messager.printMessage(Diagnostic.Kind.ERROR, "Unexpected error in EventBusAnnotationProcessor: " + e);
}
return true;
}
private void createInfoIndexFile(String index)方法会生成一个新的class
/** 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往索引中添加相关的信息
putIndex(new SimpleSubscriberInfo(com.study.sangerzhong.studyapp.ui.MainActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEvent", com.study.sangerzhong.studyapp.ui.MainActivity.DriverEvent.class, ThreadMode.POSTING, 0, false),
// 类中每一个被Subscribe标识的方法都在这里添加进来
}));
}
// 下面的代码就是EventBusAnnotationProcessor中写死的了
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;
}
}
将生成的索引信息类交给EventBus,这样在查找信息的时候会从索引集合中去匹配
EventBus.builder().addIndex(new MyEventBusIndex()).build()
public EventBusBuilder addIndex(SubscriberInfoIndex index) {
if (subscriberInfoIndexes == null) {
subscriberInfoIndexes = new ArrayList<>();
}
subscriberInfoIndexes.add(index);
return this;
}
五、总结
将所有需要被调用的方法的状态记录下来(所属类,参数),在需要调用的时候,通过反射调用
网友评论