EventBus已经出来很久了,相信大家并不陌生,很多android程序员应该在项目中都使用过它了,当然了我也使用过,以前使用的时候就是觉得它使用起来挺简单的,但是它的具体实现原理却没有研究过,作为一名有追求的程序员,仅仅会使用是无法满足我的,今天我们就从源码来看看他是如何实现的。
EventBus的作用就是方便应用的各个部分之间的通信,且能降低彼此之间的耦合。
使用EventBus第一步就是要获取它的实例,看一下它提供的方法:
EventBus.getDefault()
public static EventBus getDefault() {
if(defaultInstance == null) {
Class var0 = EventBus.class;
synchronized(EventBus.class) {
if(defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
可以看到他使用的是双重判断的单列模式,并且考虑了并发问题。
使用EventBus主要分为两步:
1. 注册 Register(Object subscriber)
public void register(Object subscriber) {
this.register(subscriber, false, 0);
}
private synchronized void register(Object subscriber, boolean sticky, int priority) {
List subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
Iterator i$ = subscriberMethods.iterator();
while(i$.hasNext()) {
SubscriberMethod subscriberMethod = (SubscriberMethod)i$.next();
this.subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
首先看方法的几个参数,目前看得懂的就是Object subscriber,因为这是我们register(param)传进去。
让我们来看看List subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
参数subscriber.getClass()返回的是subscriber这个对象所属的类对象(java.lang.Class),这个对象是在类加载过程中生成的,它主要是作为方法区中这个类的各个数据的访问入口(小说一句,该对象存在于HotSpot虚拟机中的方法区里面)。
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
String key = subscriberClass.getName();
Map clazz = methodCache;
List subscriberMethods;
synchronized(methodCache) {
subscriberMethods = (List)methodCache.get(key);
}
if(subscriberMethods != null) {
return subscriberMethods;
} else {
ArrayList var23 = new ArrayList();
Class var24 = subscriberClass;
HashSet eventTypesFound = new HashSet();
for(StringBuilder methodKeyBuilder = new StringBuilder(); var24 != null; var24 = var24.getSuperclass()) {
String name = var24.getName();
if(name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
break;
}
Method[] methods = var24.getDeclaredMethods();
Method[] arr$ = methods;
int len$ = methods.length;
for(int i$ = 0; i$ < len$; ++i$) {
Method method = arr$[i$];
String methodName = method.getName();
if(methodName.startsWith("onEvent")) {
int modifiers = method.getModifiers();
if((modifiers & 1) != 0 && (modifiers & 5192) == 0) {
Class[] parameterTypes = method.getParameterTypes();
if(parameterTypes.length == 1) {
String modifierString = methodName.substring("onEvent".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")) {
if(!this.skipMethodVerificationForClasses.containsKey(var24)) {
throw new EventBusException("Illegal onEvent method, check for typos: " + method);
}
continue;
}
threadMode = ThreadMode.Async;
}
Class eventType = parameterTypes[0];
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(methodName);
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
if(eventTypesFound.add(methodKey)) {
var23.add(new SubscriberMethod(method, threadMode, eventType));
}
}
} else if(!this.skipMethodVerificationForClasses.containsKey(var24)) {
Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + var24 + "." + methodName);
}
}
}
}
if(var23.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called " + "onEvent");
} else {
Map var25 = methodCache;
synchronized(methodCache) {
methodCache.put(key, var23);
return var23;
}
}
}
}
2-10行:通过我们传入对象的类名作为键在一个map集合中查找对应的值,如果查找到了就直接返回。
22-23行:通过我们之前获得的java.lang.Class类对象利用反射去获取该类里面所有的方法。
26-66行:遍历该类中所有的方法,如果是以“onEvent”开头,并且该方法的修饰符是public且非static和abstract方法,并且该方法只有一个参数,就可以进入到封装的代码中。通过截取该方法名onEvent后面的字符串与“MainThread”,“BackgroundThread”,“Async”进行对比来确定threadMode,它是一个枚举,eventType是该方法的参数Class对象,将该方法的method,threadMode,eventType作为参数封装到一个SubscriberMethod对象当中,并将该对象添加到一个ArrayList集合当中并返回,在返回之前会吧这个以传入的类名作为键,这个ArrayList集合作为值缓存到methodCache这个map集合中,下次就可以直接从缓存中拿到ArrayList对象了。
List subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
Iterator i$ = subscriberMethods.iterator();
while(i$.hasNext()) {
SubscriberMethod subscriberMethod = (SubscriberMethod)i$.next();
this.subscribe(subscriber, subscriberMethod, sticky, priority);
}
接下来就是继续遍历我们刚才获取到的ArrayList对象,将得到的subscriberMethod 对象作为参数传入subscribe(subscriber, subscriberMethod, sticky, priority)这个方法,我们再去看看这个方法里面做了什么:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
Class eventType = subscriberMethod.eventType;
CopyOnWriteArrayList subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventType);
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
if(subscriptions == null) {
subscriptions = new CopyOnWriteArrayList();
this.subscriptionsByEventType.put(eventType, subscriptions);
} else if(subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
}
int size = subscriptions.size();
for(int subscribedEvents = 0; subscribedEvents <= size; ++subscribedEvents) {
if(subscribedEvents == size || newSubscription.priority > ((Subscription)subscriptions.get(subscribedEvents)).priority) {
subscriptions.add(subscribedEvents, newSubscription);
break;
}
}
Object var14 = (List)this.typesBySubscriber.get(subscriber);
if(var14 == null) {
var14 = new ArrayList();
this.typesBySubscriber.put(subscriber, var14);
}
((List)var14).add(eventType);
if(sticky) {
Map var11 = this.stickyEvents;
Object stickyEvent;
synchronized(this.stickyEvents) {
stickyEvent = this.stickyEvents.get(eventType);
}
if(stickyEvent != null) {
this.postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
}
}
}
还好这个方法没有那么长,让我们来分析一下:
首先创建了一个Subscription对象,将之前封装对象里面的eventType(方法参数的Class 对象)作为键,创建一个List集合作为值添加到了一个concurrentHashmap对象subscriptionsByEventType中,后序就是通过这个对象来查找我们想要调用的方法并通过反射调用(这里只是先提一下)。
之前有几个参数我们没看懂,比如priority,当传入相同参数类型有多个方法的时候,将刚生产的Subscription按优先级的大小来确定位置添加到List集合当中。
Object var14 = (List)this.typesBySubscriber.get(subscriber);
if(var14 == null) {
var14 = new ArrayList();
this.typesBySubscriber.put(subscriber, var14);
}
((List)var14).add(eventType);
if(sticky) {
Map var11 = this.stickyEvents;
Object stickyEvent;
synchronized(this.stickyEvents) {
stickyEvent = this.stickyEvents.get(eventType);
}
if(stickyEvent != null) {
this.postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
}
}
将方法参数的Class对象添加到var14 就是一个List集合中,并将这个List集合作为值和传入的subscriber作为键添加到一个map集合中typesBySubscriber。
2. 发布 Post(Object event)
public void post(Object event) {
EventBus.PostingThreadState postingState = (EventBus.PostingThreadState)this.currentPostingThreadState.get();
List 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()) {
this.postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
让我们来分析一下发布方法里面做了些什么:
1.将post(Object event)参数event对象添加到一个list集合。
2.第6行判断当前是否是UI线程,并且把isPosting属性设置为true。
3.然后会走到一个循环当中 当list集合不为空,会调用postSingleEvent方法,好吧 我们去看下这个方法。
4.最后会吧 isPosting和isMainThread都设置为false。
private void postSingleEvent(Object event, EventBus.PostingThreadState postingState) throws Error {
Class eventClass = event.getClass();
boolean subscriptionFound = false;
if(this.eventInheritance) {
List eventTypes = this.lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for(int h = 0; h < countTypes; ++h) {
Class clazz = (Class)eventTypes.get(h);
subscriptionFound |= this.postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = this.postSingleEventForEventType(event, postingState, eventClass);
}
if(!subscriptionFound) {
if(this.logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if(this.sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) {
this.post(new NoSubscriberEvent(this, event));
}
}
}
首先看到这个方法lookupAllEventTypes(eventClass)
private List<Class<?>> lookupAllEventTypes(Class<?> eventClass) { Map var2 = eventTypesCache; synchronized(eventTypesCache) { Object eventTypes = (List)eventTypesCache.get(eventClass); if(eventTypes == null) { eventTypes = new ArrayList(); for(Class clazz = eventClass; clazz != null; clazz = clazz.getSuperclass()) { ((List)eventTypes).add(clazz); addInterfaces((List)eventTypes, clazz.getInterfaces()); } eventTypesCache.put(eventClass, eventTypes); } return (List)eventTypes; } }
这个方法会得到一个List集合,里面装的是我们pos传入参数event对象的Class,以及他的父类和接口的Class对象。
接着会遍历这个List集合,获得其中的每一个Class对象,然后调用了postSingleEventForEventType(event, postingState, eventClass)方法,再进入这个方法
private boolean postSingleEventForEventType(Object event, EventBus.PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized(this) {
subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventClass);
}
if(subscriptions != null && !subscriptions.isEmpty()) {
Iterator i$ = subscriptions.iterator();
while(i$.hasNext()) {
Subscription subscription = (Subscription)i$.next();
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
this.postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if(aborted) {
break;
}
}
return true;
} else {
return false;
}
}
subscriptionsByEventType 有没有很熟悉啊??? 对了就是之前那个存放方法参数的Class对象为键,Subscriptions为值得那个concurrentHashmap对象,这个通过这个对象将post(Object event)参数的Class对象作为键的值取出来,这如果这个event的Class对象跟之前那个方法参数的Class对象是同一个对象,那么取出来的不就是之前存的Subscriptions对象吗?而Subscriptions集合里面装着newSubscription对象,newSubscription对象里面封装了所有需要的信息,在看postToSubscription(subscription, event, postingState.isMainThread)方法
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch(EventBus.SyntheticClass_1.$SwitchMap$de$greenrobot$event$ThreadMode[subscription.subscriberMethod.threadMode.ordinal()]) {
case 1:
this.invokeSubscriber(subscription, event);
break;
case 2:
if(isMainThread) {
this.invokeSubscriber(subscription, event);
} else {
this.mainThreadPoster.enqueue(subscription, event);
}
break;
case 3:
if(isMainThread) {
this.backgroundPoster.enqueue(subscription, event);
} else {
this.invokeSubscriber(subscription, event);
}
break;
case 4:
this.asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
当threadMode枚举为1是说明找到的是onEvent()方法,并利用反射调用;当threadMode为2的时候说明找到的是onEventMainThread()方法,然后判断是否是主线程,如果是主线程就反射调用,如果不是,就将放入队列中。当threadMode为3的时候说明找到的是onEventBackgroundThread()方法,同样判断发送事件如果是在主线程,就将其放入队列,如果是子线程就直接利用发射调用,当threadMode为4的时候说明是调用onEventAsync()方法,它会将其放入队列并在合适的时候反射调用。
好了,到这里EventBus的源码大致分析清楚了,但还有一小部分没有分析,比如boolean sticky这个参数是干什么用的?registerSticky()这个构造函数有什么不同?下次再跟大家一起分析了。