EventBus的基本用法
注册事件
EventBus.getDefault().register(this);
解除注册
EventBus.getDefault().unregister(this);
发送事件
EventBus.getDefault().post(event);
处理事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void XXX(Object event) {
...
}
注解@Subscribe
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
/**
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
*/
boolean sticky() default false;
/** Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s! */
int priority() default 0;
}
这是一个自定义的运行时注解,有三个属性,threadMode、sticky、priority。
threadMode表示处理事件所在的线程,有POSTING、MAIN、BACKGROUND和ASYNC四种线程模型,默认为POSTING。
sticky是否是粘性事件,默认为false。
priority为优先级,默认值为0,值越大优先级越高。
EventBus的getDefault()
EventBus.getDefault()采用单例模式,创建一个EventBus对象,初始化了subscriptionsByEventType和typesBySubscriber两个HashMap,用以存储订阅者、订阅方法和订阅事件的相关信息。
//这是一个单例模式
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
//创建了一个EventBus对象
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
//一个HashMap,以事件类型eventType为key,以存储了订阅者和订阅方法的集合CopyOnWriteArrayList<Subscription>为value
subscriptionsByEventType = new HashMap<>();
//一个HashMap,以订阅者subscriber为key,以订阅者所订阅的事件类型eventType的集合List<Class<?>>为value
typesBySubscriber = new HashMap<>();
//粘性事件相关的集合,这里不对粘性事件做分析,有兴趣的自行学习
stickyEvents = new ConcurrentHashMap<>();
//主线线程事件发送者
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
//后台线程事件发送者
backgroundPoster = new BackgroundPoster(this);
//异步线程事件发送者
asyncPoster = new AsyncPoster(this);
...
}
注册register
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//获取订阅者的订阅方法的集合,后面有对findSubscriberMethods的描述
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
//Subscription封装了订阅者subscriber和订阅方法subscriberMethod
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
//subscriptions若为空,先初始化,subscriptions已包含newSubscription,说明已被注册过,抛异常
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++) {
//按优先级把newSubscription添加到subscriptions,即添加到subscriptionsByEventType
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);
}
//把eventType添加到subscribedEvents,即添加到typesBySubscriber
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);
}
}
}
从上面代码可以看出,注册其实就是把当前订阅者相关的所有newSubscription存入subscriptionsByEventType,把当前订阅者订阅的所有eventType存入typesBySubscriber。
因为newSubscription包含了订阅者subscriber和订阅方法subscriberMethod,subscriptionsByEventType的key为事件类型eventType,
所以在subscriptionsByEventType中可以根据事件类型eventType获取所有的类型为eventType的订阅方法subscriberMethod。因为typesBySubscriber的key为订阅者subscriber,所以在typesBySubscriber中可以根据订阅者subscriber获取订阅者订阅的所有的事件类型eventType。
subscriberMethodFinder.findSubscriberMethods(subscriberClass)
方法findSubscriberMethods是为了获取订阅者的订阅方法的集合List<SubscriberMethod>,查看findSubscriberMethods这个方法的源码可以发现如果不使用索引,最终会调用findUsingReflectionInSingleClass方法,而默认是不使用索引的,对索引感兴趣的请自行学习,下面是findUsingReflectionInSingleClass方法的源码:
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;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
//方法名前有public,没有abstract、static
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)) {
//获取注解中的threadMode
ThreadMode threadMode = subscribeAnnotation.threadMode();
//findState.subscriberMethods是一个List<SubscriberMethod>集合,创建订阅方法SubscriberMethod添加到集合中
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");
}
}
}
从上面源码中可以看出,集合findState.subscriberMethods就是我们要获取的集合,最后通过getMethodsAndRelease(FindState findState)从FindState中获取这个集合
解除注册unregister
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
//根据订阅者subscriber获取订阅者订阅的所有的事件类型
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
//从subscriptionsByEventType中移除订阅者对应的subscription
unsubscribeByEventType(subscriber, eventType);
}
//移除订阅者订阅的所有的事件类型
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
/*
*从subscriptionsByEventType中移除订阅者对应的subscription,subscription包含subscriberMethod,
*所以其实是从subscriptionsByEventType中移除订阅者对应的处理eventType类型事件的方法subscriberMethod
*/
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//获取所有的类型为eventType的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);
//判断是否是当前订阅者subscriber
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
从上面代码可以看出,解除注册其实就是从typesBySubscriber中移除订阅者订阅的所有的事件类型eventType,从subscriptionsByEventType中移除所有当前订阅者对应的处理eventType类型事件的方法subscriberMethod。
发送事件post
post方法最终调用的是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);
}
}
从上面可以看出发送者和处理函数在相同线程直接调用invokeSubscriber,不相同时,分别调用mainThreadPoster.enqueue、backgroundPoster.enqueue和asyncPoster.enqueue。其中mainThreadPoster.enqueue是通过Handler将消息发送到主线程最终再调用invokeSubscriber,而backgroundPoster.enqueue和asyncPoster.enqueue都是通过调用线程池的线程的run方法最终调用invokeSubscriber,所以postToSubscription方法最终调的都是invokeSubscriber方法,只是所在线程不同罢了。
从invokeSubscriber的源码可以看出,它通过反射调用处理事件的方法,方法的参数是event。
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维护了subscriptionsByEventType和typesBySubscriber两个HashMap,其中typesBySubscriber的key为订阅者subscriber,value为订阅者订阅的所有的事件类型eventType的集合,便于注册和解除注册时添加移除当前订阅者订阅的事件类型。subscriptionsByEventType的key为eventType,value为由订阅者和处理eventType类型事件的方法subscriberMethod组成的subscription对象的集合,便于发送事件时通过事件类型eventType获取处理对应事件的方法,最后通过反射机制调用该方法。
欢迎关注.jpg
网友评论