EventBus 是一款在 Android 开发中经常使用的发布/订阅事件总线框架,将事件的接收者和发送者分开;简化了组件之间的通信,使用简单、效率高、体积小!由于经常使用到,所以我们深入理解该框架的原理就很有必要了,下面我们就来分析一下EventBus原理。
大家都知道当我们在使用EventBus时,首先会调用EventBus.getDefault()方法来获取EventBus的实例。那我们来看一下getDefault()方法,代码如下:
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
这是一个双重检查模式单例模式。
接下来是EventBus构造方法,代码如下:
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}
这里DEFAULT_BUILDER是默认的EventBusBuilder:
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
这里调用了EventBus的另外一个构造方法,采用了建造者模式,通过构造EventBusBuilder来配置EventBus。
获取到EventBus的实例以后就调用register(this)方法将订阅者注册到EventBus中,register()方法代码如下:
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//得到一个SubscriberMethod的集合,就是传进来的订阅者的所有订阅方法
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {//遍历订阅者的订阅方法来完成订阅者的注册操作
subscribe(subscriber, subscriberMethod);
}
}
}
register方法做了两件事:一件事是查找订阅者的订阅方法,另一件事是订阅者的注册。
SubscriberMethod类主要用来保存订阅方法的Method对象、线程模式、事件类型、优先级、是否是黏性事件等属性。
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class> eventType;
final int priority;
final boolean sticky;
/** Used for efficient comparison */
String methodString;
public SubscriberMethod(Method method, Class> eventType, ThreadMode threadMode, int priority, boolean sticky) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.priority = priority;
this.sticky = sticky;
}
....
....
其他方法
....
....
}
接下来看看findSubscriberMethods(subscriberClass)方法代码:
List findSubscriberMethods(Class> subscriberClass) {
List subscriberMethods = METHOD_CACHE.get(subscriberClass);//从缓存中查找是否有订阅方法的集合
if (subscriberMethods != null) {//如果找到就return
return subscriberMethods;
}
//如果缓存中没有,则根据 ignoreGeneratedIndex属性的值来选择采用何种方法来查找订阅方法的集合
//ignoreGeneratedIndex 的默认值是 false,可以通过EventBusBuilder来设置它的值
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 {
METHOD_CACHE.put(subscriberClass, subscriberMethods);//找到订阅方法的集合后,放入缓存
return subscriberMethods;
}
}
ignoreGeneratedIndex 属性表示是否忽略注解器生成的 MyEventBusIndex,具体可以看官网:http://greenrobot.org/eventbus/documentation/subscriber-index/
项目中经常通过EventBus单例模式来获取默认的EventBus对象,也就是ignoreGeneratedIndex为false的情况,这种情况调用了findUsingInfo(subscriberClass)方法,代码如下:
private List findUsingInfo(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);//获取订阅者信息
if (findState.subscriberInfo != null) {
//如果我们通过EventBusBuilder配置了MyEventBusIndex,便会获取到subscriberInfo
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();//得到订阅方法相关的信息
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {//没有配置MyEventBusIndex
findUsingReflectionInSingleClass(findState);//将订阅方法保存到findState中
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);//对findState做回收处理并返回订阅方法的List集合
}
在开始查找订阅方法的时候并没有忽略注解器为我们生成的索引 MyEventBusIndex。
如果我们通过EventBusBuilder配置了MyEventBusIndex,便会获取subscriberInfo(这个参考上面ignoreGeneratedIndex为true的情况所调用的方法findUsingReflection(subscriberClass));
没有配置MyEventBusIndex便会执行findUsingReflectionInSingleClass(findState)方法;
最后再通过getMethodsAndRelease(findState)方法对findState做回收处理并返回订阅方法的List集合,这里贴一下getMethodsAndRelease(findState)方法代码:
private List getMethodsAndRelease(FindState findState) {
List 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;
}
}
}
return subscriberMethods;
}
默认情况下是没有配置MyEventBusIndex的,所以就会调用findUsingReflectionInSingleClass(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;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
//根据方法的类型、参数和注解来找到订阅方法。找到订阅方法后将订阅方法的相关信息保存到findState中。
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class>[] parameterTypes = method.getParameterTypes();
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()));
}
}
} 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");
}
}
}
上面register方法里面遍历SubscriberMethod对所有的订阅方法进行注册,调用了subscribe(subscriber, subscriberMethod)方法,代码如下:
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType;
//根据subscriber(订阅者)和subscriberMethod(订阅方法)创建一个Subscription(订阅对象)
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//根据eventType(事件类型)获取Subscriptions(订阅对象集合)
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
//如果Subscriptions为null则重新创建,并将Subscriptions根据eventType保存在subscriptionsByEventType中
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> subscribedEvents = typesBySubscriber.get(subscriber);//通过subscriber获取subscribedEvents事件类型集合
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();//为空重新创建对象
typesBySubscriber.put(subscriber, subscribedEvents);//根据subscriber将subscribedEvents存储在typesBySubscriber集合中
}
subscribedEvents.add(eventType);//将eventType添加到subscribedEvents中
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).
//从stickyEvents事件保存队列中取出该事件类型的事件发送给当前订阅者
Set, Object>> entries = stickyEvents.entrySet();
for (Map.Entry, 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);
}
}
}
subscribe()方法主要就是做了两件事:
1、将Subscriptions根据eventType封装到subscriptionsByEventType中,将subscribedEvents根据subscriber封装到typesBySubscriber中;
2、对黏性事件的处理。
我们通过post方法来对事件进行发送,所以我们看一下post()方法源码:
/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List
PostingThreadState 保存事件队列和线程状态信息,currentPostingThreadState.get()方法获取到PostingThreadState 对象,currentPostingThreadState代码如下:
private final ThreadLocal currentPostingThreadState = new ThreadLocal() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
上面从PostingThreadState对象中取出事件队列,然后再将当前的事件插入事件队列;通过postSingleEvent(eventQueue.remove(0), postingState)方法处理和移除该事件,代码如下:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
//eventInheritance 表示是否向上查找事件的父类,它的默认值为 true,可以通过在EventBusBuilder中进行配置
if (eventInheritance) {
List> eventTypes = lookupAllEventTypes(eventClass);//找到所有的父类事件并存在List中
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()方法的代码:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);//同步取出该事件对应的Subscriptions订阅对象集合
}
if (subscriptions != null && !subscriptions.isEmpty()) {
//遍历Subscriptions,将事件 event 和对应的 Subscription(订阅对象)传递给postingState
for (Subscription subscription : subscriptions)
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);//调用postToSubscription方法对事件进行处理。
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
接下来看postToSubscription(subscription, event, postingState.isMainThread)方法代码:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
//取出订阅方法的threadMode,根据threadMode来分别处理
switch (subscription.subscriberMethod.threadMode) {
// 默认的线程模式,在那个线程发送事件就在那个线程处理事件
case POSTING:
invokeSubscriber(subscription, event);
break;
// 在主线程处理事件
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);// 如果在主线程发送事件,则直接在主线程通过反射处理事件
} else {
// 如果是在子线程发送事件,则将事件入队列,通过Handler切换到主线程执行处理事件
mainThreadPoster.enqueue(subscription, event);
}
break;
// 无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
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);
}
}
根据threadMode来分别处理。如果threadMode是MAIN,提交事件的线程是主线程,则通过反射直接运行订阅的方法;若其不是主线程,则需要mainThreadPoster 将我们的订阅事件添加到主线程队列中。mainThreadPoster是HandlerPoster类的一个实例,继承自Handler,通过Handler将订阅方法切换到主线程执行,看下该类的主要实现,代码如下:
public class HandlerPoster extends Handler implements Poster {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
// 用subscription和event封装一个PendingPost对象
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);// 加入队列
if (!handlerActive) {
handlerActive = true;
// 发送开始处理事件的消息,handleMessage()方法将被执行,完成从子线程到主线程的切换
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {// 死循环遍历队列
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();// 出队列
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);// 进一步处理pendingPost
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
取消注册就调用unregister()方法,代码如下所示:
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List> subscribedTypes = typesBySubscriber.get(subscriber);//通过subscriber找到subscribedTypes事件类型集合
if (subscribedTypes != null) {
for (Class> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);//遍历 subscribedTypes
}
typesBySubscriber.remove(subscriber);//将subscriber对应的eventType从 typesBySubscriber中移除
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
接下来看unsubscribeByEventType(subscriber, eventType)方法,代码如下:
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class> eventType) {
//通过eventType来得到对应的Subscriptions订阅对象集合
List subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
//如果Subscription(订阅对象)的subscriber(订阅者)属性等于传进来的subscriber,则从Subscriptions中移除该Subscription
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);//移除该Subscription
i--;
size--;
}
}
}
}
以上就是EventBus的源码分析。