说明
EventBus是Android常用的三方框架之一。通过发送通知,在其他页面去做一些同步的事情,方便快捷。类似于观察者(但并不是),当观察到某个数据变化,就会立刻做改变,但是和内部和观察者其实不一样,它的思想是AOP切面编程思想。内部代码不多,大概30个类。
源码分析
1) 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的所有方法调用都需要通过EventBus.getDefault()调用,getDefault()其实就是获取的一个全局单例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);
}
其内部调用了一个有参的构造函数,传入了一个default_builder,这个default_builder就是EventBusBuilder。
有参的EventBus
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
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;
}
EventBus最终的初始化是在这里,这里做了很多处理。依次分析下构造函数中属性的含义。
1.1) subscriptionsByEventType
首先是subscriptionsByEventType,它的类型是Map<Class<?>, CopyOnWriteArrayList>,这里可以看出来,这个subscriptionsByEventType存放的是当前订阅者里面的所有注册方法。
Subscription这个类就是方法的实现,看一下里面代码:
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;
Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
active = true;
}
@Override
public boolean equals(Object other) {
if (other instanceof Subscription) {
Subscription otherSubscription = (Subscription) other;
return subscriber == otherSubscription.subscriber
&& subscriberMethod.equals(otherSubscription.subscriberMethod);
} else {
return false;
}
}
@Override
public int hashCode() {
return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
}
}
可以看到这个类中的代码其实很少,里面就是存放了就是一个Object类型的subscriber(注册的时候传进来的订阅者类),一个SubscriberMethod,里面存放的是这个subscriber中注册方法的数据。
SubscriberMethod
/** Used internally by EventBus and generated subscriber indexes. */
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;
}
@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();
}
}
SubscriberMethod内部存放的就是方法的数据,其中method就是需要执行的方法。通过反射获取到的。
threadMode是线程类型,包括
- POSTING:事件发送者在哪个线程,那么就在哪个线程回调@Subscribe所注解的方法,同时这是默认也是官方推荐的模式
- MAIN:无论事件发送者在那种线程,都在ui线程中回调,如果发送者不再主线程,那就通过handler切换线程
- MAIN_ORDERED:在ui线程中回调,但是它永远都通过handlerpost来切换线程,通过消息队列来进行,无论发送者在哪个线程,所以肯定能够避免ui线程阻塞
- BACKGROUND:在子线程中回调被注解的方法,同样如果事件发送者就在子线程,那么直接回调了,如果不在的话,就会利用BackgroundPoster来切换线程
- BackgroundPoster是线程Runnable
ASYNC:代表回调的线程跟事件发送的线程总是不在一个线程
eventType事件类型,因为EventBus是通过参数类class去区分执行方法的,所以这个eventType的类型就是Class<?>
priority分发优先级
sticky是否粘性分发,在粘性分发的情况下,注册者比发送者更晚注册也可以收到。
1.2) typesBySubscriber
类型Map<Object, List<Class<?>>>,key是订阅者,value是当前订阅者中订阅的类型
1.3) stickyEvents
类型Map<Class<?>, Object>,粘性事件
1.4) mainThreadPoster
类型HanderPoster,继承实现了Handler,在ThreadMode切换到主线程执行的时候,通过Handler进行线程通讯,内部handlerMessage实现了一个死循环,通过不断获取自定义的PendingPostQueue消息队列,以及消息体PendingPost,处理消息。调用handler的时候是通过HanderPoster内部的enqueue方法调用,内部是对PendingPostQueue队列的操作。
final class HandlerPoster extends Handler {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
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);
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;
}
}
}
1.5) backgroundPoster
后台执行方法处理。类型BackgroundPoster,其内部是一个Runnbale,在ThreadMode是BACKGROUND的时候会调用,它也是通过PendingPostQueue队列来管理数据,在run方法中实现了死循环,通过enqueue方法调用添加消息。
主要注意的是在enqueue方法中,PendingPostrQueue执行的时候是添加了同步锁的,所以说明该方法一次只会执行一条数据处理。
final class BackgroundPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
1.6) asyncPoster
后台执行方法处理。类型AsyncPoster,其内部也是一个Runnbale,在ThreadMode是ASYNC的时候会调用。它会每次启动一个新线程,且enqueue是直接执行,没有同步锁,所以可能会并发,并且将该poster存放到线程池。run方法也会直接执行处理。
class AsyncPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
AsyncPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
}
1.7) EventBusBuilder
配置部分EventBus的设置,将一些配置同意存放到了EventBusBuilder中。
2) register()
事件注册,EventBus必须在需要在响应的类中注册和取消注册,register就是注册方法。
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
首先方法中传递的subscriber是我们的注册者,也就是我们常使用的activity或者fragment(但是不是一定只有这两个),首先通过getClass方法获取到当前Object的类型。然后通过subscriberMethodFinder.findSubscriberMethods获取到当前类中所以已经注册的方法,然后遍历这个list,将其添加到方法集合map中。
2.1) subscriberMethodFinder.findSubscriberMethods
首先subscriberMethodFinder是在EventBus的构造方法中初始化的。
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
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;
}
}
方法首先通过METHOD_CACHE获取方法列表,其中METHOD_CACHE是当前所有已经注册了的方法的集合缓存。如果这个集合中存在相同可以的数据,也就是list不为空的时候,就直接返回这个数据。
如果过去不到,缓存中没有数据,那就通过反射获取到当前类中所有的方法,然后判断方法中是否存在注解,如果存在就返回方法(findUsingReflectionInSingleClass())。
2.2) subscriber()
最终执行订阅方法的方法。内部主要逻辑,就是将类和方法绑定到subscriptionsByEventType和typesBySubscriber中,在这里subscriber()在方法的最后处理了粘性event的list,通过遍历stickyEvents,并且处理当前订阅者是否需要接受粘性事件。
3) unregister()
取消订阅,和register成对出现,通常在页面销毁时调用,主要处理就是在subscriptionsByEventType和typesBySubscriber中移除对应数据
/** Unregisters the given subscriber from all event classes. */
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);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
4) 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 = Looper.getMainLooper() == Looper.myLooper();
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;
}
}
}
首先获取当前线程,然后获取到当前线程的消息队列Queue,然后将当前post的消息添加到队列中。然后判断当前线程是否在post消息,如果没有就执行下面代码,首先判断是否在主线程执行,然后通过postSingleEvent()发送队列中的第一条消息,并将该消息从队列中移除。
4.1) 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);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
在方法中, lookupAllEventTypes(eventClass)是在事件类型缓存中查找是否存在相同的事件类型,如果存在就直接返回,如果不存在就创建。然后通过postSingleEventForEventType()调用postToSubscription(subscription, event, postingState.isMainThread)方法,最终在postToSubscription方法中去执行处理。
4.2) 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中,通过ThreadMode类型,判断是否直接去执行调用方法还是通过handler或者backgroundPoster等去执行。最终都会调用invokeSubscriber()方法处理
4.3) 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);
}
}
最终都是调用Method.invoke去执行该方法。
5) postSticky()
粘性事件发送,通过postSticky发送,当发送粘性事件后,在事件不移除的情况下,先发送,后注册的订阅者也可以收到消息。
/**
* 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);
}
通过源码其实看出来,它内部也是同post调用,不同的是其传递的event添加到了stickyEvents中了。然后在stickyEvents中,post后会处理已经订阅了的事件,然后在新订阅的页面,在register的时候,调用subscriber()方法(章节2.2)后去判断是否需要执行该stickyEvents里面的方法。
Sunanang