如果有朋友对EventBus的使用还不熟悉,建议看看
http://www.jianshu.com/p/887421af4cc1
(1)从构造方法入手
EventBus.getDefault()
单例模式
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
然后看看new EventBus()
public EventBus() {
this(DEFAULT_BUILDER);
}
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
然后看看this()方法做了什么
一系列的初始化操作
EventBus(EventBusBuilder builder) {
//记住这个map,它的key是订阅方法的类型(也就是订阅方法的参数类型),value是一个list,后面会用到
subscriptionsByEventType = new HashMap<>();
//记住这个map,它的key是订阅者,参数是该订阅者的所有订阅放方法的参数类型的集合,后面会用到
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的第三个参数传入的是默认值false,后面会用到
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;
}
(2)接着看register()方法
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//寻找该类中所有的订阅方法,就是有@Subscribe的那些方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
//把这些方法注册到EventBus
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
我们先看SubscriberMethod是什么
//这里包含了我们在写订阅方法所要考虑的那些
public class SubscriberMethod {
final Method method;//方法
final ThreadMode threadMode;//在哪个线程执行
final Class<?> eventType;//参数类型
final int priority;//优先级
final boolean sticky;//是否是粘性方法
/** Used for efficient comparison */
String methodString;
...
}
再看
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//如果内存中有就直接在内存中取
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
////是否忽略注解器生成的MyEventBusIndex类
//ignoreGeneratedIndex这个参数我们在第一步就说明了,默认为false
if (ignoreGeneratedIndex) {
//利用反射来获取订阅类中的订阅方法信息
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//所以我们要看这个方法
//从注解器生成的MyEventBusIndex类中获得订阅类的订阅方法信息
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;
}
}
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//FindState其实就是一个里面保存了订阅者和订阅方法信息的一个实体类,包括订阅类中所有订阅的事件类型和所有的订阅方法等
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
//findState.subscriberInfo 这个变量在FindState初始化的时候被设置为null,所以这里先不用看
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//着重看这个方法
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(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) {
//获取方法的声明,比如public,abstract,static等
int modifiers = method.getModifiers();
//该方法必须是public,而且不能是MODIFIERS_IGNORE
//private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
//获取方法的参数
Class<?>[] parameterTypes = method.getParameterTypes();
//参数只能有1个
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
//该方法必须有Subscribe注解
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
//校验是否添加该方法,具体怎么校验的大家可以自己看看源码
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
//把该方法添加到list集合
//这个list集合的声明是final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
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的List<SubscriberMethod> subscriberMethods = new ArrayList<>()里面
我们再返回去看看findUsingInfo()这个方法,这个方法最终的返回
getMethodsAndRelease(findState)
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> 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;
}
到这里就把我们FindState中的subscriberMethods集合返回了,经过以上步骤我们得到了类中的所有订阅的方法
下面我们看看怎么注册这些方法,就是register()方法的后半部分
//这个方法的第一个参数是订阅者,第二个参数是该订阅者的所有订阅方法
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);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
//当重复执行register()方法就会报此异常
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//根据优先级将订阅者和订阅方法组成的newSubscription添加到list里面,
//这个list存放的是订阅方法类型相同的Subscription.
//优先级高的放到list的前面位置
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;
}
}
//typesBySubscriber它的key是订阅者,参数是该订阅者的所有订阅放方法的参数类型的集合
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
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);
}
}
}
至此,register()方法结束,虽然代码很多,但是总结起来就是维护了两个主要的map
subscriptionsByEventType:它的key是订阅方法的类型(也就是订阅方法的参数类型),value是一个list
typesBySubscriber:它的key是订阅者,参数是该订阅者的所有订阅放方法的参数类型的集合
我们可以猜测,unregister()方法就是在这两个map中移除相应的订阅者和订阅方法
(3)下面看下事件分发post()
public void post(Object event) {
//获取当前线程的postingState
//currentPostingThreadState = new ThreadLocal<PostingThreadState>()
PostingThreadState postingState = currentPostingThreadState.get();
//取得当前线程的事件队列
List<Object> eventQueue = postingState.eventQueue;
//把该事件加入到事件队列里面,等待分发
eventQueue.add(event);
//postingState.isPosting默认为false
if (!postingState.isPosting) {
//判断是否是在主线程
//Looper.getMainLooper() 获取的是主线程的looper
//Looper.myLooper()获取的是当前线程的looper
//二者相同则说明当前线程就是主线程
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;
}
}
}
下面看看PostingThreadState是什么
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>();//当前线程的事件队列
boolean isPosting;//是否有事件正在分发
boolean isMainThread;//post的线程是否是主线程
Subscription subscription;//订阅者和订阅方法组成
Object event;//订阅事件
boolean canceled;//是否取消
}
PostingThreadState中包含了当前线程的事件队列,以及订阅者订阅事件等信息,有了这些信息我们就可以从事件队列中取出事件分发给对应的订阅者。
//参数一是post()方法的参数,参数二是PostingThreadState
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
//这里默认为false不执行
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));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//还记得subscriptionsByEventType吗?
//在第2步最后我们总结了subscriptionsByEventType的作用
//它的key是订阅方法的类型(也就是订阅方法的参数类型),value是一个list
//这个list包含所有的订阅者以及订阅者的订阅方法
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;
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
//根据订阅方法的threadMode来进行区分
//对于这四种类型的理解,这里不再赘述,如果不明白,请参考我写的
//EventBus使用详解
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()方法做了什么
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的源码,还有unregister()方法没有说,但是我在第2步后面也简单的说了下,具体是怎么实现的,大家自己去探索吧
最后简单的总结下:
订阅过程:
①通过register()方法注册一个订阅者
②找到该订阅者里面的所有订阅方法
③根据订阅事件类型,把相关信息存入到subscriptionsByEventType中,这是一个以订阅事件类型为key,订阅者和订阅事件组成的subscription的list为value的map
④根据订阅者,将相关信息存入到typesBySubscriber中,它的key是订阅者,参数是该订阅者的所有订阅放方法的参数类型的集合
分发过程:
①获取当前线程的事件队列,并把要发送的事件添加到队列中
②根据发送事件类型获取所有的订阅者
③通过反射执行订阅者的订阅方法