Android开发中咱们最经常使用到的能够说就是EventBus了,今天咱们来深刻研究一下EventBus的源码。java
先简单回顾下EventBus最基本的使用方法:git
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
复制代码
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
复制代码
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
复制代码
EventBus.getDefault().post(new MessageEvent("Hello world!"));
复制代码
使用EventBus基本须要四步,咱们分析源码主要着重与后两步,也就是三个方法: EventBus.getDefault().register(this); 、EventBus.getDefault().post(new MessageEvent("Hello world!"));、EventBus.getDefault().unregister(this);。以这三个方法为入口来切入EventBus的源码分析,会使咱们对EventBus的整个流程更加清晰。github
public void register(Object subscriber) {
//1.获取订阅者的Class对象
Class<?> subscriberClass = subscriber.getClass();
//经过反射获取订阅者中开发人员定义的处理事件的方法集合
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//将获取的订阅者和订阅者中处理事件的方法按照必定的规则相结合并存储到EventBus内部
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
复制代码
我把register这个方法主要分为三部分。第一步很简单了,获取订阅者的Class对象,这个订阅者一般就是咱们写的Activity或者Fragment等等。第二步是经过咱们第一步拿到的订阅者的Class对象,反射获取全部符合规则的处理事件的方法。既然要 符合规则的方法 ,那么规则是什么呢?其实规则就是这些方法必须加 @subscribe 注解,参数必须有且只有一个等等。咱们来看一下代码:缓存
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;
}
}
复制代码
在findSubscriberMethods这个方法中,主要是进行了对订阅者中咱们定义的处理事件的方法的获取操做。代码逻辑其实已经比较清晰了,首先是从缓存中拿方法集合,有的话直接返回,没有的话再去获取。第二步是获取的关键,它比较复杂,咱们暂时先看第三步。若是当前获取到的方法集合为空,则抛出异常。看到这里小伙伴们应该就比较熟悉了,在咱们刚开始使用EventBus的时候常常会在一个Activity中调用的EventBus的register方法,可是却忘了写**@subscribe**注解的方法,运行程序会报错。那么很明显,就是这里抛出了一个异常,这个异常提醒咱们,若是在订阅者中调用的register方法,就必须添加至少一个相应的处理事件的方法。若是获取到的方法集合不为空,则将之放入缓存并返回。bash
这个findSubscriberMethods方法中最关键的是第二步的获取。这里有一个变量 ignoreGeneratedIndex,是否忽略索引,默认值为false,也就是默认不忽略索引,走的是else中的 findUsingInfo(subscriberClass); 方法。那么问题来了,这个索引是什么,为何咱们日常使用EventBus的时候历来都没用过这个东西?其实在EventBus3.0以前是没有索引这个东西的,第二步获取方法集合走的是 findUsingReflection(subscriberClass); 这个方法。那为何在3.0以后加上了索引呢?其实答案很简单,就是由于反射获取方法集合是比较低效的,使用反射所耗费的时间开销比较大。若是使用索引,EventBus的性能会提高一倍。具体如何在你的代码中使用EventBus的索引,能够参考 greenrobot官网中index的介绍 。那么小伙伴们问题又来了,既然是默认不忽略索引,而咱们平时使用EventBus根本没添加过索引相关的代码,那 findUsingInfo(subscriberClass); 这段代码到底是使用什么方式来获取方法集合的呢?放代码:并发
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
//若是咱们没有添加相关索引的配置,那么findState.subscriberInfo=null,走的是else中的方法
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);
}
复制代码
在 findUsingInfo 这段代码中,咱们忽略细节,只看我添加注释的部分。若是添加了索引相关的配置,代码会去执行索引相关的逻辑;反之,代码执行 findUsingReflectionInSingleClass(findState); 这个函数,经过反射来获取方法集合。咱们忽略索引部分,跟进 findUsingReflectionInSingleClass(findState); 这个方法看一下:async
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) {
int modifiers = method.getModifiers();
//必须是PUBLIC方法.....
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();
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");
}
}
}
复制代码
这个方法就很清楚了。首先经过反射拿到全部方法的集合,而后遍历这个集合,筛选出符合规则的方法,也就是咱们写的处理事件的方法。到这里小伙伴们应该很清楚了,变量ignoreGeneratedIndex默认是false,走的是索引的处理,可是我平时没写过索引的配置,因此最后仍是走的反射,经过反射获取方法集合。ide
register方法中的第二步到这里就大体说完了,下面咱们开始第三步。代码上面有,我再贴一遍方便你们看。函数
synchronized (this) {
//遍历方法集合
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
复制代码
这段代码很简单,遍历第二步获取的方法集合,调用 subscribe(subscriber, subscriberMethod); 这个方法。很明显,subscribe(subscriber, subscriberMethod); 是最后一步的核心代码,咱们跟进去看一下:oop
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//获取方法中的事件类型
Class<?> eventType = subscriberMethod.eventType;
//将订阅者和方法绑在一块儿造成一个Subscription对象
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//将newSubscription加入eventType所对应的subscriptions集合中
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//避免重复订阅
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
//按照priority优先级将newSubscription加入subscriptions集合中
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
//初始化 typesBySubscriber 这个成员变量,造成 订阅者 -> 订阅者可以接收的事件类型集合 的关系
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
//加入新的事件类型
subscribedEvents.add(eventType);
//若是方法能够接收sticky事件
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>).
//遍历stickEvents这个map
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
//若是找到了跟这个方法的eventType一致的stickEvent
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
//发送事件,本质是经过反射直接调用这个方法
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
//
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
复制代码
这段代码就比较多了,咱们来捋一下它的思路。这个方法接收2个参数Object subscriber, SubscriberMethod subscriberMethod,第一个参数是咱们的订阅者,第二个参数是对咱们写的处理事件的方法的封装。方法内部首先经过Class<?> eventType = subscriberMethod.eventType;
获取了一个eventType,表明的是处理事件方法中参数的类型,比方说:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
复制代码
在这个例子中eventType指的就是MessageEvent.Class。下一步经过Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
将订阅者和方法封装绑定。接下来的话subscriptionsByEventType这个变量是EventBus中的一个成员变量,经过名字咱们也能够知道,这个一个map,它的主要功能就是经过eventType来获取subscriptions这个Subscription类的集合。咱们看一下这个成员变量的定义:
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
复制代码
跟咱们说的同样,subscriptionsByEventType是一个map,它的key存的是eventType,value存的是Subscription的集合。继续看下一段代码:
//按照priority优先级将newSubscription加入subscriptions集合中
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;
}
}
复制代码
记不记得若是要确保事件的处理须要有前后顺序,那么咱们须要在事件处理方法上添加priority的注解。这段代码就是把优先级高的放到list的首部,优先级低的放到后面,经过这种方式实现了不一样方法对同一事件处理的优先级问题。继续看代码:
//初始化 typesBySubscriber 这个成员变量,造成 订阅者 -> 订阅者可以接收的事件类型集合 的关系
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
复制代码
这段代码核心是初始化typesBySubscriber这个成员变量,它的结构和subscriptionsByEventType相似,key是subscriber订阅者,value是eventType的集合。接下来是最后一段代码:
//若是方法能够接收sticky事件
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>).
//遍历stickEvents这个map
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
//若是找到了跟这个方法的eventType一致或是其子类的stickEvent
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
//发送事件,本质是经过反射直接调用这个方法
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
复制代码
粘性事件相信你们都用过,这段代码首先判断了处理事件的方法是否有stick这个注解,若是存在则进入下一步。eventInheritance这个变量默认为true,表明事件是否具备继承性。能够这么理解,发送一个事件或者发送这个事件类型的子类,EventBus的处理事件方法中的参数类型是父类型,那么这个方法既能够收到父类型的事件,也能够收到子类型的事件。那小伙伴们要问了,那若是处理事件方法中的参数类型是子类型呢?那这个方法就只能接收子类型的事件,而没法接收父类型的事件。在if (eventType.isAssignableFrom(candidateEventType))
这一行代码作了判断,isAssignableFrom这个方法是JDK中Class类中的一个方法,做用就是判断前者是不是与后者类型一致或前者是后者的父类。下面这个代码就很简单了checkPostStickyEventToSubscription(newSubscription, stickyEvent);
发送事件,咱们跟进去看一下:
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
// --> Strange corner case, which we don't take care of here. postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper()); } } 复制代码
这个方法的功能很简单,对事件作了非空校验,而后调用了postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
方法,这个方法本质就是经过反射调用method.invoke(subscription.subscriber, event);
来执行咱们定义的对事件的处理方法。这个方法很重要,我会在讲post方法的时候着重分析,咱们暂时只须要知道它的功能便可。看到这里,小伙伴们应该就能明白,为何在粘性事件发出后再注册的事件处理方法能够接收到它了,由于以前发送的stickyEvent都会存入stickyEvents这个map类型的EventBus中的成员变量中,当咱们注册调用register方法时,在register方法内部会直接经过checkPostStickyEventToSubscription(newSubscription, stickyEvent);
来执行咱们定义的粘性事件处理方法。
至此,咱们终于说完了register这个方法,这个方法的内容看似只有短短几行,但它所作的事情仍是很繁琐复杂的。下面咱们来对上面对register的分析来作个总结:
咱们经常使用的post有两种:post和postSticky,先来看postSticky:
public void postSticky(Object event) {
synchronized (stickyEvents) {
//全部发出的sticky事件都会存入stickyEvents这个map中
stickyEvents.put(event.getClass(), event);
}
// 调用普通的post方法
post(event);
}
复制代码
postSticky结构分为两块:将全部发出的sticky事件存入stickyEvents这个map中,关于stickyEvents这个EventBus中的成员变量咱们在register方法中已经说过,再也不赘述。以后会调用post方法,因此咱们的重点仍是post方法:
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循环来不断发送事件队列中的事件,直到事件队列为空
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
复制代码
忽略代码细节的话,post仍是很好理解的。在发送事件的当前线程中会存储一个线程状态的变量postingState,这个变量包含了当前线程中的一些重要信息,咱们来看一下它的组成:
final static class PostingThreadState {
//事件队列
final List<Object> eventQueue = new ArrayList<Object>();
//是否正在发送事件
boolean isPosting;
//是不是主线程
boolean isMainThread;
Subscription subscription;
Object event;
//是否已经取消
boolean canceled;
}
复制代码
能够看到,PostingThreadState为当前线程存储了不少有用的信息:事件队列、是否正在发送事件、是不是主线程、subscription、事件、是否已经取消。
继续看post的代码,将发送的事件加入到了当前线程中的事件队列中。以后就是一个while循环,不断发送事件队列中的事件,直到事件队列中再也不包含任何事件。循环中发送事件的方法是postSingleEvent,咱们跟进去看一下是如何发送的:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
//获取事件类型
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
//事件是否具备继承性,默认为true
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));
}
}
}
复制代码
这个方法核心只有两部分:获取事件类型、发送事件。有一个变量你们可能会有些疑惑,eventInheritance表明是否容许事件发送这个事件的全部父类型事件,默认为true,也就是说在发送一个子类事件时,EventType是父类的事件处理方法也能够收到当前事件。举个栗子:
@Subscribe()
public fun onReceiveObject(data: Any) {
Observable.timer(
1,
TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe() {
toast("any")
}
}
@Subscribe()
public fun onReceiveDataItem(data: DataItem) {
Observable.timer(
2,
TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe() {
toast("dataItem")
}
}
复制代码
这是两个kotlin写的事件处理方法,第一个接收的事件类型是Any,对kotlin不熟悉的小伙伴能够理解为Object类型;第二个接收的事件类型是DataItem。咱们都知道,Object类确定是DataItem的父类。我下面提两个问题,若是发送Object类型的事件,会发生什么?若是发送DataItem类型的事件,会发生什么?
相信若是你们真正理解了postSingleEvent这个方法的话,这个问题不难回答。若是发送Object类型,会显示any的Toast;若是发送DataItem类型,则会显示any和dataItem的Toast。从上面的代码分析咱们能够知道,在发送一个事件的时候,EventBus默认会找到这个事件类型全部的父类型并发送。
在postSingleEvent这个方法中发送事件的方法是postSingleEventForEventType,咱们继续跟进去看代码:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
//根据事件类型找到subscriptions
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
//变量subscriptions,发送事件
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;
}
复制代码
代码本事逻辑很简单:根据subscriptionsByEventType找到事件eventClass对应的subscriptions,相信这些变量你们都很熟悉了。以后会遍历subscriptions,调用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);
}
}
复制代码
整段代码按照线程分为四个部分来处理。POSTING表明着当前线程,在哪一个线程发送事件,就在哪一个线程处理事件;MAIN表明只在主线程处理事件;BACKGROUND表明只在非主线程处理事件;ASYNC也是表明在非主线程处理事件。
BACKGROUND和ASYNC都是在非主线程处理事件,那么两者有什么区别呢? 从代码中能够直观的看到:BACKGROUND的逻辑是若是在主线程,那么会开启一条新的线程处理事件,若是不在主线程,那么直接处理事件;而ASYNC的逻辑则是无论你处于什么线程,我都新开一条线程处理事件。
咱们从上到下把这四种类型解释一下: POSTING中调用了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);
}
}
复制代码
核心代码只有一句:subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
也很好理解,经过反射执行事件处理方法。
MAIN中首先判断当前线程是不是主线程,若是是,则执行invokeSubscriber,经过反射直接执行事件处理方法。反之则经过mainThreadPoster.enqueue(subscription, event);
来执行事件的处理,那么它是如何切换线程的呢?答案很简单mainThreadPoster实际上是一个主线程中的Handler,调用mainThreadPoster.enqueue(subscription, event);
会触发它的handleMessage方法,在这个方法中最终调用的是eventBus.invokeSubscriber(pendingPost);
。能够看到经过handler机制进行了线程的切换,在handleMessage中依旧是调用invokeSubscriber方法经过反射来执行事件处理方法。
BACKGROUND中首先判断是否在主线程,若是是则调用backgroundPoster.enqueue(subscription, event);
。backgroundPoster跟mainThreadPoster不同,backgroundPoster是一个Runnable,enqueue其实是开启了一个线程,在这个新的线程中再执行invokeSubscriber这个方法。若是不在主线程,则直接调用invokeSubscriber。
ASYNC中asyncPoster和上面提到的backgroundPoster同样,也是一个Runnable,它的enqueue实际上也是开启了一个线程,在这个新的线程中再执行invokeSubscriber这个方法。
至此为止post方法终于讲完了,咱们来总结一下:
终于到最后一个方法了,unregister方法。不废话,看代码:
public synchronized void unregister(Object subscriber) {
//获取订阅者全部订阅的事件类型
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
//遍历事件类型集合
for (Class<?> eventType : subscribedTypes) {
//从subscriptionsByEventType中删除订阅者的相关信息
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
复制代码
这个方法的核心内容就是删除全局变量subscriptionsByEventType中全部包含当前订阅者的subscription,这也就很好的解释了为何在解绑后咱们不会再收到EventBus发送的事件了。由于发送事件的核心是根据事件类型从subscriptionsByEventType中获取subscriptions这个集合,遍历集合经过subscription能够拿到subscriber和subscriberMethod,以后再经过subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
,采用反射来进行事件的处理。unregister方法删除了全局变量subscriptionsByEventType中全部包含当前订阅者的subscription,在遍历subscriptions的时候是不会获取包含当前订阅者的subscription,因此天然不会再收到事件。
其实看完上面的分析,熟悉观察者模式的小伙伴们应该很清楚了,搞了这么多,其实EventBus不就是个观察者模式么。没错,EventBus的本质就是个观察者模式,常见的被观察者只有一个,而观察者的个数不肯定。被观察者内部维持着一个观察者的集合,当被观察者要发送事件时会遍历内部的观察者集合,拿到观察者并调用观察者的相关方法。观察者的描述是否是和EventBus的整个流程很是一致?简而言之,EventBus就是一个被观察者,它的内部存放着一个subscriptionsByEventType集合,这个集合包含了咱们全部的观察者,也就是调用了register的全部Activity或者Fragment等等。当使用post发送事件时,会遍历subscriptionsByEventType,拿到观察者,经过反射调用观察者中的事件处理方法。你没看错,EventBus的核心逻辑就是这么简单,仅仅只是一个观察者模式。
再多扯几句,有些小伙伴可能看完上面一大堆东西仍是感受不是很明白,不要紧,很正常,谁也不太可能任何东西看一遍就了然于胸的。个人建议是能够打开Android Studio边看源码边看个人分析,不明白的跟进去看源码就好。
最后,但愿你们能经过这篇分析加深对EventBus和观察者模式的理解,感谢你们。