EventBus框架总结之用法 总结了EventBus的基本用法。俗话说,“知其然,必知其所以然”,所以本文通过阅读EventBus的源码来了解它的实现原理。
EventBus是通过观察者模式来实现的消息总线,观察者模式必然包括订阅者、被订阅者、订阅事件、取消订阅事件、发布事件五个角色和动作,那么本文就从这五个角色和动作着手分析EventBus。
Register :是如何进行事件订阅的呢?
EventBus的第一步是通过Register来进行注册,那就从Register来分析是如何进行事件订阅的以及其中的订阅者和被订阅的对象分别对应着什么。
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//获取订阅信息
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//订阅
subscribe(subscriber, subscriberMethod);
}
}
}
EventBus的 register() 中通过subscriberMethodFinder.findSubscriberMethods 来获取订阅的信息,从命名上来看应该是获取 subscriber 中与EventBus相关方法的信息,从源码上来求证
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
//通过EventBus.GetDefault()时,ignoreGeneratedIndex为false
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//通过EventBus.GetDefault()时,调用此函数
subscriberMethods = findUsingInfo(subscriberClass);
}
/..其他代码被删除,减少篇幅../
} else {
//通过反射去读取注解,因此采取了内存缓存,减少反射带来的性能影响
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
通过EventBus.getDefault()调用时时,ignoreGeneratedIndex为false,所以会执行到findUsingInfo()方法,METHOD_CACHE 进行内存缓存,减少反射带来的性能影响
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
/..去除其他代码../
} else {
//最终调用 findUsingReflectionInSingleClass 去获取信息
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
findUsingInfo最终会调用到findUsingReflectionInSingleClass去获取EventBus相关的方法信息,继续往下看
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
//获取订阅对象的所有方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
// Modifier.PUBLIC 这里进行判断,EventBus回调的方法必须是public,不然直接会跳过
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
//这里进行判断,EventBus回调的方法的参数个数必须是1,不然直接会跳过
if (parameterTypes.length == 1) {
//通过读取方法注解设置的属性
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//参数类型
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
//注解设置的线程模型、优先级、粘性等属性
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky(), genericsType));
}
}
}
}
}
}
findUsingReflectionInSingleClass中通过获取所有的方法并进行筛选,只有方法为public且参数长度为1的函数才会继续读取,然后通过读取方法注解信息,并存储在findState,然后回到findUsingInfo()调用getMethodsAndRelease(findState)来获取SubscriberMethod的信息,也就是获取register(object)中object满足EventBus回调的方法的信息。
然后再回到register()方法中,通过findSubscriberMethods获取了subscriberMethods信息,subscriberMethods才是观察者模式中真正的订阅者们,然后调用subscribe()来对满足EventBus要求的订阅者们进行订阅
SubscriberMethod:真正的订阅者
通过上面的分析,EventBus中真正的订阅者们SubscriberMethod浮出了水面
//真正的订阅者
public class SubscriberMethod {
//方法
final Method method;
//线程模型
final ThreadMode threadMode;
//参数类型
final Class<?> eventType;
//优先级
final int priority;
//黏性
final boolean sticky;
}
SubscriberMethod包含方法、线程模型、参数类型、优先级等信息
subscribe():事件的订阅
在register()中,获取SubscriberMethod信息之后,调用subscribe()来进行订阅
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
//订阅信息
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
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);
}
}
//订阅的优先级设置,priority越大优先级越高
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) {
/..黏性相关代码,省略,../
}
}
Subscription:订阅信息,包含发起订阅动作的对象,以及真正的订阅者
final class Subscription {
final Object subscriber;//发起订阅动作的对象,register函数的参数
final SubscriberMethod subscriberMethod;//订阅者
}
subscriptionsByEventType:一个map,key为被订阅事件,value为订阅了该被订阅事件的订阅者们,用于保存被订阅事件与订阅者的关系
typesBySubscriber:用于保存发起订阅动作的对象与它所包含的被订阅事件的对应关系,用于unregister来取消订阅事件
post():发布事件
EventBus.getDefault().post(event)发布事件,先贴源码
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
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 {
//读取队列上的事件进行post,直到所有事件发布成功
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
post一个事件时,首先将事件加入队列,然后判断当前是否正在发布,若没有发布,则开始事件发布。这里若是当前正处于发布状态,只是把事件加入到了队列里面,没有做其他处理
//读取队列上的事件进行post,直到所有事件发布成功
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
通过上面这段代码可以了解到,若处于发布状态,那肯定while循环会一直从队列上取出事件并进行发布,直到队列上没有事件为止,所以当处于发布状态时,只需要加事件加入到队列即可
PostingThreadState,来用记录当前发布线程的状态。
final static class PostingThreadState {
//事件队列
final List<Object> eventQueue = new ArrayList<Object>();
boolean isPosting;//当前是否正处于发布
boolean isMainThread;//当前发布是否处于主线程
Subscription subscription;//正在发布事件的订阅信息
Object event;//正在发布的事件
boolean canceled;//是否被取消
}
通过postSingleEvent()进行发布
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = 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);
}
/..没有发现订阅信息处理../
其中lookupAllEventTypes()函数,通过递归读取其直接和间接父类以及实现的接口,并分别调用postSingleEventForEventType进行发布,也就是说发布事件时,会间接触发它的父类和接口的事件触发。例如Message继承MessageBase,若发布Message事件时,同时会发布MessageBase事件
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发布事件
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;
}
postSingleEventForEventType 会调用postToSubscription进行事件的发布
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 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);
}
}
postToSubscription中看到了我们熟悉的切换线程,也就是EventBus实现它的线程模型的地方,通过subscription.subscriberMethod.threadMode来进入不同的模型,通过之前的分析,subscriberMethod中的threadMode就是通过读取方法注解中的threadMode值来进行设置,就实现了通过注解进行线程模型设置,这里就不一一对所有的线程模型进行分析了,看看invokeSubscriber()是如何工作的
void invokeSubscriber(Subscription subscription, Object event) {
try {
//通过反射invoke方法并传入event subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
从invokeSubscriber()中可以了解到,最后调用反射来调用函数。
unregister():取消事件订阅
还是先贴代码
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);
}
}
从前面的分析中已经了解到typesBySubscriber用于保存发起订阅动作的对象与它所包含的被订阅事件的对应关系,用于unregister来取消订阅事件;从typesBySubscriber中获取subscriber这个订阅事件发起者中所涉及的事件,调用unsubscribeByEventType来取消订阅
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--;
}
}
}
}
通过事件来获取对其进行订阅了的所有订阅信息,若是同一个发起者,则将订阅的事件移除来取消订阅
总结
register(object) :发起订阅, 其中object为订阅发起者
unregister(object) :取消订阅,其中object为取消订阅发起者
SubscriberMethod :正在的订阅者
Subscription :订阅信息,包含订阅者和订阅发起者
Event :被订阅者(事件)
post:发布事件
subscriptionsByEventType :保存了被订阅者与订阅信息(订阅者和订阅发起者)之间的对应关系
typesBySubscriber :订阅发起者与事件之间的对应关系,用于unregister