public void register(Object subscriber) {
register(subscriber, false, 0);
}
private synchronized void register(Object subscriber, boolean sticky, int priority) {
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
当Eventbus注册之后实际上是在这里面对这个类的所有方法做了一个遍历检测,然后筛选出符合条件的方法,这里面有一个订阅的概念,相当于Eventbus帮我们筛选出合适的方法,然后封装成一个SubscriberMethod对象,这个对象里面包含了筛选出来的方法的属性,包括方法名,参数类型,也就是说Eventbus帮我们订阅监听了这些方法,这些事情是在subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());里面做的:
List findSubscriberMethods(Class subscriberClass) {
String key = subscriberClass.getName();
List subscriberMethods;
synchronized (methodCache) {
subscriberMethods = methodCache.get(key);
}
if (subscriberMethods != null) {
return subscriberMethods;
}
subscriberMethods = new ArrayList();
Class clazz = subscriberClass;
HashSet<String> eventTypesFound = new HashSet<String>();
StringBuilder methodKeyBuilder = new StringBuilder();
while (clazz != null) {
String name = clazz.getName();
if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
// Skip system classes, this just degrades performance
break;
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
ThreadMode threadMode;
if (modifierString.length() == 0) {
threadMode = ThreadMode.PostThread;
} else if (modifierString.equals("MainThread")) {
threadMode = ThreadMode.MainThread;
} else if (modifierString.equals("BackgroundThread")) {
threadMode = ThreadMode.BackgroundThread;
} else if (modifierString.equals("Async")) {
threadMode = ThreadMode.Async;
} else {
if (skipMethodVerificationForClasses.containsKey(clazz)) {
continue;
} else {
throw new EventBusException("Illegal onEvent method, check for typos: " + method);
}
}
Class eventType = parameterTypes[0];
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(methodName);
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
if (eventTypesFound.add(methodKey)) {
// Only add if not already found in a sub class
subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
}
}
} else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."
+ methodName);
}
}
}
clazz = clazz.getSuperclass();
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
+ ON_EVENT_METHOD_NAME);
} else {
synchronized (methodCache) {
methodCache.put(key, subscriberMethods);
}
return subscriberMethods;
}
}
这里面还做了一个缓存优化,如果之前这个对象已经regist过并且还未unRegist,那么对象方法的订阅信息会保存在methodCache里面,key就是类名,这时候要是有同一个类的对象,无论是不是同一个对象,都将直接去methodCache里面去取相关的方法订阅信息,如果methodCache没有这个类的订阅信息,那么就继续往下执行,首先:
if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
// Skip system classes, this just degrades performance
break;
}
首先,jdk android sdk系统类全部屏蔽,接着方法名必须是以“onEvent”(ON_EVENT_METHOD_NAME = “onEvent”)开头的,方法参数必须是只有一个参数,方法必须是public类型,且不能是static,abstract修饰的方法,然后就接下去分析方法全名:
String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
ThreadMode threadMode;
if (modifierString.length() == 0) {
threadMode = ThreadMode.PostThread;
} else if (modifierString.equals("MainThread")) {
threadMode = ThreadMode.MainThread;
} else if (modifierString.equals("BackgroundThread")) {
threadMode = ThreadMode.BackgroundThread;
} else if (modifierString.equals("Async")) {
threadMode = ThreadMode.Async;
}
从这里可知订阅的方法必须是onEvent,onEventMainThread,onEventBackground,onEventAsync四种才可被订阅
先总结下能被成功订阅的方法条件:
1. 只有onEvent,onEventMainThread,onEventBackground,onEventAsync这四种方法能被订阅
2. public方法,并且不能是static,abstract修饰
3. 方法的参数只能是一个
然后我们来看下Eventbus里面定义的一些线程模型:
1. PostThread:当前线程,对应onEvent()方法,也就是说onEvent()方法里面执行的代码和当前调用onEvent()方法的线程属于同一个线程,可能是主线程,也可能是单独的线程
2. MainThread:主线程,对应onEventMainThread(),onEventMainThread()方法里面的代码一定只会在主线程中执行,所以可以在onEventMainThread()方法中直接进行UI更新操作,但是不能进行耗时操作
3. BackgroundThread:后台线程,对应onEventBackground(),如果当前线程是主线程,那么onEventBackground()里面的代码会被单独开一个线程来执行,如果当前的线程已经属于后台线程,那么onEventBackground()里面的代码将会直接在这个后台线程里面执行,不能执行UI操作,
4. Async:单独的异步线程,对应onEventAsync(),无论onEventAsync()所在的线程是在主线程或者是在后台线程,onEventAsync()里面的代码都会被单独开辟一个新的线程来执行,所以在这里面可以执行一些异步操作,但是不能执行UI操作
比较:BackgroundThread和Async的区别就在于Async里面可以执行耗时较长操作,因为每个操作都是一个单独的线程,但是BackgroundThread就不能执行耗时较长的操作,BackgroundThread的后台线程是排队执行的,如果有一个耗时较长的操作在BackgroundThread里面执行,那么会导致其他的BackgroundThread事件分发延迟,因为BackgroundThread正在执行上一个任务
继续往下分析:
SubscriberMethod是一个订阅方法的信息类,一个订阅方法对应一个SubscriberMethod,如果订阅类里面有多个订阅方法,这个订阅类将会有一个SubscriberMethod的列表信息,里面保存了订阅方法,被订阅的方法的线程模型,以及订阅方法的参数类型,以下就是SubscriberMethod的信息:
final Method method;
final ThreadMode threadMode;
final Class eventType;
/** Used for efficient comparison */
String methodString;
SubscriberMethod(Method method, ThreadMode threadMode, Class eventType) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
}
在订阅方法都遍历初始化完成后会生成一个SubscriberMethod的List,然后把这个List保存在一个全局的map当中,至此注册结束
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List
事件对象首先是被添加到一个List列表中,其中PostingThreadState是当前线程的分发事件的一些状态记录,其中也包含了一个List事件列表,只要是同一个线程的事件分发都会被添加到这里面来,然后就开始反复的从List列表中去取出事件并且post出去,执行的是postSingleEvent(eventQueue.remove(0), postingState):
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) {
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(event, postingState, eventClass),继续把事件信息往下传递:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class eventClass) {
CopyOnWriteArrayList 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(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
刚才注册的时候不是把订阅对象的信息都保存到一个map里面了吗,就是这个subscriptionsByEventType,这里从subscriptionsByEventType中get出跟事件对象类型相匹配的订阅方法信息,继续把事件对象往下传递postToSubscription(subscription, event, postingState.isMainThread):
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case PostThread:
invokeSubscriber(subscription, event);
break;
case MainThread:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BackgroundThread:
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);
}
}
好了,一层一层传递下来这里才是真正调用刚才订阅的那四个方法(onEvent,onEvent…)的代码,很明显,采用的是反射机制来调用的,大家最后都调用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);
}
}
直接采用反射执行上述四个方法,于是乎,你在regist的时候的那个Object里面的四个onEvent等方法就能被成功调用执行了
现在来讨论下Eventbus是如果实现后台线程,主线程运行的,可以看到主线程采用mainThreadPoster.enqueue(subscription, event)执行,后台线程采用backgroundPoster.enqueue(subscription, event)执行,单独的异步线程采用asyncPoster.enqueue(subscription, event)执行,一个一个来看;
mainThreadPoster.enqueue(subscription, event):
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
构造方法:
HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
mainThreadPoster是一个Handler,它直接跟主线程的Looper绑定,mainThreadPoster里面维护了一个队列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;
}
}
所以对于多个事件分发到主线程中执行是一个一个执行的,而不是并发的,可以保证先post的先执行
BackgroundPoster是一个Runnable:
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;
}
}
}
话不多,还是用队列来保证先post的先执行
AsyncPoster类:
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);
}
}
AsyncPoster跟BackgroundPoster实现类似,区别就在于BackgroundPoster在事件压入队列后在run方法里面循环poll出事件来执行,而AsyncPoster是把事件压入队列后直接单独开一个线程执行。没听明白是不?前面不是提到BackgroundThread和Async线程模型的区别在于BackgroundThread要是执行耗时较长的任务会导致后面的事件延迟执行而Async则不会,因为AsyncPoster的enqueue()方法在把事件压入事件队列后立刻eventBus.getExecutorService().execute(this),而eventBus.getExecutorService()是Executors.newCachedThreadPool()创建的线程池,没有线程数的限制,所以事件来几个就执行几个;而BackgroundPoster的enqueue()在把事件压入事件队列后只会执行一次eventBus.getExecutorService().execute(this),然后在run方法中开启循环来从事件队列里面取出事件来执行eventBus.invokeSubscriber(pendingPost),invokeSubscriber()方法就是反射执行onEventBackGround()方法,如果在onEventBackGround()里面耗时太久,那么这次循环就一直没结束,无法进入下一次循环所以会造成BackgroundThread线程模型的事件一直分发下来压入队列,但是一直无法执行,只有等上一个耗时任务执行完成才能继续下一个
总结,Eventbus的几个核心类
1. EventBus,这是个单例,主要是维护注册对象的订阅方法信息,对外提供Eventbus的使用接口
2. SubscriberMethod 订阅方法信息封装对象
3. AsyncPoster,BackgroundPoster,HandlerPoster保证订阅方法在各个执行的线程模型里面执行
4. PendingPostQueue订阅事件的队列实现
final class PendingPostQueue {
private PendingPost head;
private PendingPost tail;
synchronized void enqueue(PendingPost pendingPost) {
if (pendingPost == null) {
throw new NullPointerException("null cannot be enqueued");
}
if (tail != null) {
tail.next = pendingPost;
tail = pendingPost;
} else if (head == null) {
head = tail = pendingPost;
} else {
throw new IllegalStateException("Head present, but no tail");
}
notifyAll();
}
synchronized PendingPost poll() {
PendingPost pendingPost = head;
if (head != null) {
head = head.next;
if (head == null) {
tail = null;
}
}
return pendingPost;
}
synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
if (head == null) {
wait(maxMillisToWait);
}
return poll();
}
}
其实PendingPostQueue只有一个头部和尾部,说是队列,其实应该端链表,PendingPost不断的next连着下一个PendingPost