EventBus大家一定不陌生,组件之间传递消息只要post一下,对方就能收到,还可以任意切换线程,究竟内部是如何完成的呢?今天就一眼究竟。
一、首先把简单的用法贴一下:
1.注册,在需要接受消息的组件内进行注册(在组件创建的位置进行注册)
EventBus.getDefault().register(this);
2.编写处理消息的方法
@Subscribe
public void getInfo(String str){
//发送的消息会在这里进行接受
}
3.发送消息在需要发送消息的组件内做如下操作
EventBus.getDefault().post("哈罗呀");这样就可以在2步的方法内接受到我们发送的消息,就是这么神奇。
4.最后一步别忘记在注册的组建内onDestory的时候对EventBus进行反注册
EventBus.getDefault().unregister(this);
二、那我们来看一下短短的几句代码背后都为我们做了些什么
1、EventBus.getDefault(),代码点进去不出意外的单例模式
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;}
标准的懒汉式单例模式,我们把完整的实例对象和构造函数贴出来看一下
static volatile EventBus defaultInstance;
public EventBus() { this(DEFAULT_BUILDER);}
有没有发现哪里不对劲,标准的单例类的实例和构造方法不是应该都是private修饰的吗,为什么会是这样呢?其实EventBus提供了两种方式来实例化Eventbus,首先就是通过单例,我们来看下这个过程
public EventBus() {
this(DEFAULT_BUILDER);
}
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
单例中new EventBus的时候构建了一个EventBusBuilder并调取了重载方法
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;
}
我们看到这里采用建造者模式帮我们初始化了一些属性,那么这些属性可不可以自己做一些特殊的定制呢?我们马上看下上面说到的第二种获取EventBus的方法
public static EventBusBuilder builder() {
return new EventBusBuilder();
}
看见没有返回一个EventBusBuilder,想到了什么,建造者模式,那么我们就可以通过这个EventBusBuilder去设置上面第一种方法给我们的默认属性,并最终通过EventBusBuilder.builder()构造出一个根据我们需求自定义的EventBus实例
EventBusBuilder builder = EventBus.builder();
builder.eventInheritance(true);
builder.installDefaultEventBus();
。。。。。。
builder.sendNoSubscriberEvent(true);
EventBus eventBus = builder.build();
上面初始化的一些map和属性我们下面用到再说。
2.我们来看下注册里面帮我们做了哪些事情EventBus.getDefault().register(this);
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods =subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}}
register的时候我们把当前的Activity传进去,我们看findSubscriberMethods方法里面都做了什么
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);//(1)
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) { //(2)
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);//(3)
}
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;
}
}
(1)首先去缓存中去查找,有的话直接返回,没有的话继续,我们是第一次进行注册缓存里面肯定是空的,我们继续向下看我们看(2)处的条件判断,ignoreGeneratedIndex这个是什么时候赋值的,如果大家细致的看过获取EventBus实例的时候那堆默认的build属性,就应该还有印象,我们看一下
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex);
继续看下builder.ignoreGeneratedIndex中的赋值
/** Forces the use of reflection even if there's a generated index (default: false). */public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) { this.ignoreGeneratedIndex = ignoreGeneratedIndex; return this;}
看注释,默认这个值是false,ok我们继续返回上面的if条件判断
那上面(2)中的条件判断应该走的是else分支findUsingInfo(subscriberClass)我们看下这个方法帮我们做了什么
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();//1
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {//这个在初始化FindState 将订阅类的class赋值给findState.clazz,这个地方为true
findState.subscriberInfo = getSubscriberInfo(findState);//2
if (findState.subscriberInfo != null) {//3
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);
}
1帮我们初始化了一个FindState,我们来看下FindState类
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
SubscriberMethod记录了订阅者类及其中的订阅方法,anyMethodByEventType
2看一下getSubscriberInfo方法做了哪些工作
private SubscriberInfo getSubscriberInfo(FindState findState) {
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null)
{ SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes)
{
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
我们在初始化FindState的时候将findState.subscriberInfo置为null,所以直接走第二个if,看一下subscriberInfoIndexes 这个是在什么时候赋值的
EventBus(EventBusBuilder builder) {
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex);
}
List<SubscriberInfoIndex> subscriberInfoIndexes;
最后发现还是在构造EventBus实例的时候赋值的,但是我们会发现builder.subscriberInfoIndexes是个空值,还有对subscriberInfoIndexes进行初始化,我们回到getSubscriberInfo方法中第二个if也没能够走进去,最后只好return null,我们再回到上面的findUsingInfo方法中的3,由于getSubscriberInfo返回null,因此这个判断语句走else分支,我们看下这个方法中做了什么findUsingReflectionInSingleClass(findState);方法太长,我们把核心代码贴出来看一下
......
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()));
}
}
......
上面省略号代码是通过反射获取注册类中的所有方法,中间代码主要把@Subscribe标注的方法找出来,并获取注册的参数信息如:标注的线程、事件的优先级、是否是粘性事件等,用获取的这些信息构建一个SubscriberMethod对象并添加到findState.subscriberMethods集合中,最后findUsingInfo方法return getMethodsAndRelease(findState),这个方法主要是将我们构造的FindState放入FIND_STATE_POOL数组中,方便下次使用,ok到此findUsingInfo就全部分析完成,通过这个方法我们最终得到了List<SubscriberMethod>,我们继续往回翻到findSubscriberMethods这个方法中的(3)位置,向下走判断subscriberMethods这个是不是空,通过上面的分析,这个是不为空的,将我们的subscriberMethods和subscriberClass放到METHOD_CACHE中,下次相同的subscriberClass类register的时候就不同走下面一大堆的方法了,直接在METHOD_CACHE中查找并返回就好了,findSubscriberMethods方法的最后将我们获取的subscriberMethods返回,我们回到register方法中
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod); }}
遍历subscriberMethods并相应在走subscribe方法,我们去看看,subscribe主要做一些绑定工作,具体代码就不贴了,把其中几个关键的容器介绍下
subscriptionsByEventType保存了相应方法的参数的.class对象为key,CopyOnWriteArrayList<Subscription> subscriptions为value的Map中
Subscription中保存了Subscriber; subscriberMethod;两个对象
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
typesBySubscriber保存了订阅者为key,以及订阅者内部相应@Subscribe标注的方法的参数的class对象的集合为value的Map
@Subscribe
public void getInfo(String str){
}
subscribedEvents.add(eventType);这个eventType就是上面String的class对象
到此我们把subscribe方法中绑定的集中关系简单介绍了下,subscribe方法中还做了粘性事件相关的绑定我们暂且先不做了解,到此我们把订阅相关的方法介绍到此结束。
三.我们看下发送事件之后都做了哪些工作,EventBus.getDefault().post("哈罗呀");
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;//1
eventQueue.add(event);//2
if (!postingState.isPosting) {//3
postingState.isMainThread = isMainThread();
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);//4
}
}
finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
currentPostingThreadState我们看到这是一个ThreadLocal,关于ThreadLocal不了解的可以了解下,这里就不多做介绍,就是一个本地线程副本变量工具类,PostingThreadState类我们上面应该也看到过,他里面记录了一些当前线程里面事件的搜集和发送状态,我们看到1处获取了PostingThreadState中维护的事件队列,2将要发送的事件放入到队列中,往下走到3的if判断中,我们看到postingState.isPosting默认是false,走进判断分支中,我们直接看关键的第四步,这里是一个while循环,会吧队列中的事件发送的同时,将事件从队列中删除,我们看下postSingleEvent方法
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {//1
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);//2
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {//3
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));
}
}
}
postSingleEvent方法中的1,eventInheritance这个值是在构建EventBus的时候初始化的boolean eventInheritance =true;默认为true,走到2lookupAllEventTypes方法中,代码补贴了,直接看一下注释
Looks up all Class objects including super classes and interfaces. Should also work for interfaces.
查找所有类对象,包括超类和接口
就是讲发送事件的class对象,包括父类和接口的所有的,放入集合中并返回List<Class<?>> eventTypes,还做了一件事情,放入到eventTypesCache中,下次同样的就直接返回。ok我们回到postSingleEvent方法的3处继续,这里for循环遍历我们刚才获取的eventTypes集合,并调用postSingleEventForEventType方法,我们看一下postSingleEventForEventType方法中的关键方法
postToSubscription(subscription, event, postingState.isMainThread);
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 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);
}
}
我们看到postToSubscription方法中会根据我们设置的不同的线程进行不同的处理,其实做的操作都是反射调用注册者内响应的方法,我们随便看一下方法具体的实现
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);//1
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e)
{
throw new IllegalStateException("Unexpected exception", e);
}
}
invokeSubscriber方法中的1处,这个我们应该不陌生就是反射调用方法把我们发送的事件event传过去,到此Eventbus基本流程就全部介绍完毕,如有不正确的地方欢迎评论区讨论。