先上代码:
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
从代码可以看出,EventBus能够在不同组件、Activity之间通信都是通过一个static的单例对象。是观察者模式的一种应用,注册—>list.add post—>通知所有注册的观察者。具体来看代码。
先来看register方法:
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass(); //获取观察者的Class
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); //获取Class中带有Subscribe注释的方法
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);//核心代码,下面会详细分析
}
}
}
在register方法中调用的subscribe方法:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType; //注册的方法所在的class
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//此对象是用来检测是否已经调用过注册
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);//全局的Map中获取所有此class注册的方法
if (subscriptions == null) {//观察者第一次调用注册(观察者class中有多个subscribe方法会调用多次)
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);//将注册对象的class和class中的注册方法放入全局Map中
} else {
if (subscriptions.contains(newSubscription)) {//此类型的Event已经在class上注册过了,抛出异常
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) {//检查优先级 优先级高的在前 默认优先级为0 可通过在观察中用 priority = X 来配置
subscriptions.add(i, newSubscription);
break;
}
}
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {//第一次调用-->新建key--value配对
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) { //是否是sticky事件(如果是粘性事件,事件总线会传递最近的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).
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);
}
}
}
上面一段代码中用到的几个成员变量:
private final Map, CopyOnWriteArrayList> subscriptionsByEventType;//存观察者的class和对应的SubcriptionList
private final Map
以上为EventBus的注册过程,代码中涉及的其他类后面会详细分析,这里只是分析流程。
EventBus为Post事件提供了两个方法post()和postSticky(),其中postSticky()内部也是通过post()实现的只不过是多了事件的保存,代码如下:
/**
* Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
* event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}.
*/
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
这里注释已经解释的很明显了"将给定的事件发布到事件总线并保持事件(因为它是粘性的)。事件类型的最新粘性事件保存在内存中,供使用{@link Subscribe#sticky()}的订阅者将来访问。"
再来看post:
/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();//获取post线程的状态,这里currentPostingThreadState被ThreadLocal修饰只能在一个线程中访问
List
post()方法中调用的postSingleEvent()方法:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List> 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) { //未找到观察者-->post一个NoSubscriberEvent
if (logNoSubscriberMessages) {
Log.d(TAG, "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);//获取class的subcriptions
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {//通知对应的观察者执行对应的方法
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;//定义post中止标志
try {
postToSubscription(subscription, event, postingState.isMainThread);//核心代码,下面分析
aborted = postingState.canceled;
} finally {//更新post状态
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {//post中止跳出循环不再post事件,返回true
break;
}
}
return true;
}
return false;
}
再来看postToSubscription():
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {//switch观察者方法执行的线程 --- 默认和post为同一个线程
case POSTING://post数据线程
invokeSubscriber(subscription, event); //通过反射调用对应方法,下面详解
break;
case MAIN://主线程
if (isMainThread) {//post线程是否是主线程
invokeSubscriber(subscription, event);//如果是主线程,直接通过反射调用对应方法
} else {//不是主线程
mainThreadPoster.enqueue(subscription, event);//通知处理主线程事件的HandlerPoster(HandlerPoster内部有一个队列,此处实际上是往队列中添加一条数据)
}
break;
case BACKGROUND://后台(如果post线程不是主线程,将在post线程中调用) 以下代码调用流程同上一个case
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC://独立于post线程和主线程 无需判断post线程直接通过处理ASYNC事件的HandlerPoster处理
asyncPoster.enqueue(subscription, event);
break;
default://抛出异常
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
上文方法中调用的invokeSubscriber():
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);
}
}
代码中多次使用到Subcription对象,构造其实也很简单,用来绑定观察者和subcribe方法,代码如下:
final class Subscription {
final Object subscriber;
final SubscriberMethod subscriberMethod;
/**
* Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
* {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
*/
volatile boolean active;//是否活动 源码注释很详细"当unregister()被调用后会置为false,通过队列事件传递进行检查”
Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
active = true;
}
@Override
public boolean equals(Object other) {//重写equals方法
if (other instanceof Subscription) {
Subscription otherSubscription = (Subscription) other;
return subscriber == otherSubscription.subscriber
&& subscriberMethod.equals(otherSubscription.subscriberMethod);//如果观察者和subscribe方法都一样的话认为是同一个Subscription对象
} else {
return false;
}
}
@Override
public int hashCode() {
return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
}
}
public class SubscriberMethod {
final Method method;//方法体
final ThreadMode threadMode;//方法执行线程
final Class> eventType;//执行method的class
final int priority;//优先级
final boolean sticky;//是否是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;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other instanceof SubscriberMethod) {
checkMethodString();
SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
otherSubscriberMethod.checkMethodString();
// Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
return methodString.equals(otherSubscriberMethod.methodString);
} else {
return false;
}
}
private synchronized void checkMethodString() {
if (methodString == null) {
// Method.toString has more overhead, just take relevant parts of the method
StringBuilder builder = new StringBuilder(64);
builder.append(method.getDeclaringClass().getName());
builder.append('#').append(method.getName());
builder.append('(').append(eventType.getName());
methodString = builder.toString();
}
}
@Override
public int hashCode() {
return method.hashCode();
}
}
将post线程不在主线程的事件发送到主线程处理的Handler
final class HandlerPoster extends Handler {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
}
EventBus 内部有维护一个Executors.newCachedThreadPool 的线程池,当调用 BackGroudPost.enqueue 的时候,会将事件弄到线程池中执行。 BackGroundPost是一个 Runnable, 内部维护一个队列,在 run 方法中会不断的从队列中取出 PendingPost,当队列没有事件时,至多等待1s,然后跳出 run 方法。
final class BackgroundPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
}
AsyncPoster 的实现跟 BackgroundPoster 的实现极为类似,区别就是是否有在 run 方法中循环取出 PendingPost。 主要的不同点就是,AsyncPost 会确保每一个任务都会在不同的线程中执行,而 BackgroundPoster 则如果发送的速度比较快且接收事件都是在 background 中,则会在同一线程中执行。
class AsyncPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
}
至此,关于EventBus3.0的代码原理分析的差不多了,当然很多细节不够详细,也还有很多相关方法没有分析到,个人认为不必太纠结于细节,分析开源框架主要是要学习思想不是么?