以前发在 CSDN 上, blog.csdn.net/u014443348/…
掘金氛围感觉更好一点,打算慢慢转过来。
源码基于 EventBus 3.0.0
EventBus
根据官方 github 的介绍,我们使用它需要三步(可以把注册拆出来,变成四步)。
- 创建一个事件类,作为消息,类似 Handler 中使用的 Message 类。(如果需要携带内容,增加成员变量)
- 增加一个处理该消息的方法,传入参数类型为上一步定义的事件类。并且增加 @Subscribe 注解。
- 在发送消息之前注册,在不使用接收之后反注册。(这里使用的是 Actitvity 中的
onStart()
与onStop()
) - 在需要发送事件消息时,使用
Event.getDefault().post(new MessageEvent())
就可以将消息发出。
从使用步骤上来说看着很简单,那我们跟着这四步的使用方法来看一看源码中的处理过程。
第一步,定义一个新的类,没什么说的。
第二步,看看 @Subscribe 注解。
@Subscribe
java 代码解读复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
/**
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
*/
boolean sticky() default false;
/** Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s! */
int priority() default 0;
}
因为该注解需要在运行时使用,查找该类中带有 @Subscribe 方法,所以 Retention 为 RetentionPolicy.RUNTIME。仅针对方法进行注解,Target 为 ElementType.METHOD。
@Subscribe 中有三个变量,先说后两个:
- sticky() 为粘性,从注释上来看,好像不太明白,那先暂时不管,后面从源码部分去寻找答案,默认设置为 false。
- priority() 为优先级,这个参数在平常接触线程中看到过,因为我们一般开发中没有对优先级有特殊要求,所以暂时也不过多关心,默认设置为 0。
- ThreadMode() 为线程模式,是一个枚举类,点开可以看到有四种模式:POSTING 、MAIN 、BACKGROUND 、 ASYNC。从名字上可以看出应该是和主线程或者非主线程以及其他情况下进行处理的。源码中解释部分太长,我就简单的翻译下:
-
- POSTING 为直接进行处理,发出消息与接收消息线程相同,这是默认情况。
-
- MAIN 为主线程模式。
-
- BACKGROUND 为后台线程模式。
-
- ASYNC 为异步模式。
POSTING 与 MAIN 模式应该比较好理解,BACKGROUND 本来也是后台,那和 ASYNC 中有什么区别 ?
注释中给出的说明是,如果是一个耗时的任务,比如网络,就使用 ASYNC模式,如果是不太耗时,就尽量使用 BACKGROUND。这个结论我们暂时先记下,一会从源码中找区别。
接下来看第三步,注册与反注册,当然先看 EventBus.getDefault()
;
getDefault()
java 代码解读复制代码
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
static volatile EventBus defaultInstance;
根据 getDefault()
能看出来是单例模式,再看 EventBus 的构造函数。
java 代码解读复制代码
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
……
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
executorService = builder.executorService;
……
}
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
EventBusBuilder() {}
能看到有两个构造函数,当然最后还是调用的带参的构造函数,能看到里面有两大类别的初始化:
- 一种是 new 出来的,比如容器 Map 类的变量。
- 一种是从 EventBusBuilder 中传递过来的。不过 EventBusBuilder 的构造函数并没有其他操作,那么 EventBus 中的某些值初始化,就是从 EventBusBuilder 中的初始值中拿到的。
有个小细节: EventBus 的构造函数修饰符,不带参数的是 public 的。
意思是我们也可以 new 一个出来。带参数的是 package 的,我们也无法调用,但我们 new 出来的 EventBus 仍然是使用内部的 DEFAULT_BUILDER ,仍然是单例。
接下来是 register()
;
register()
java 代码解读复制代码
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
看看大概逻辑,先拿到对应的订阅对象的 class,然后调用 subscriberMethodFinder.findSubscriberMethods(subscriberClass)
获得一个 SubscriberMethod 列表。
再让每个订阅方法进行订阅,看着好像不太多,那我们一步一步来。先找找 subscriberMethodFinder 这个是从哪来的。
java 代码解读复制代码
EventBus(EventBusBuilder builder) {
……
subscriberMethodFinder = new SubscriberMethodFinder(
builder.subscriberInfoIndexes,
builder.strictMethodVerification,
builder.ignoreGeneratedIndex);
}
SubscriberMethodFinder(List subscriberInfoIndexes,
boolean strictMethodVerification,
boolean ignoreGeneratedIndex) {
this.subscriberInfoIndexes = subscriberInfoIndexes;
this.strictMethodVerification = strictMethodVerification;
this.ignoreGeneratedIndex = ignoreGeneratedIndex;
}
public class EventBusBuilder {
……
boolean ignoreGeneratedIndex;
boolean strictMethodVerification;
List subscriberInfoIndexes;
}
subscriberMethodFinder 是在 EventBus 中的构造函数中初始化的,三个参数的值,都是从 builder 中传入的。
但是我们第一次初始化的时候,EventBusBuilder 对应三个参数变量肯定都是 false 与 null。确定了这个之后,我们看回 findSubscriberMethods()
。
findSubscriberMethods()
java 代码解读复制代码
List findSubscriberMethods(Class> subscriberClass) {
List 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;
}
}
private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>();
先从 METHOD_CACHE 中查找该类是否存入过列表,很显然,我们第一次使用,是没有的所以 subscriberMethods == null
,看下面一步。
ignoreGeneratedIndex 从上面的构造方法说过,这个值没有初始化过,所以传入的 false,那我们走 findUsingInfo()
。
java 代码解读复制代码
private List findUsingInfo(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
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);
}
先来看 prepareFindState()
。
java 代码解读复制代码
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
static class FindState {
final List subscriberMethods = new ArrayList<>();
final Map anyMethodByEventType = new HashMap<>();
final Map subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class> subscriberClass;
Class> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
……
}
FindState 类,大概浏览下成员变量,就是一个存储信息的一个类。FIND_STATE_POOL 是一个保存 FindState 的数组,初始大小为 4。
因为这个数组,之前也没有调用的,长度为 4 ,但是每个值都是 null,for 循环找不到一个非 null ,默认返回一个 new FindState。接下来是 findState.initForSubscriber(subscriberClass)
;
java 代码解读复制代码
void initForSubscriber(Class> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
对 subscriberClass 与 class 赋值之后,while (findState.clazz != null)
至少第一次是满足的,我们看进去。
java 代码解读复制代码
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;
}
emmm …… 我们好像都没有,所以返回 null。
java 代码解读复制代码
if (findState.subscriberInfo != null) {
……
} else {
findUsingReflectionInSingleClass(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) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
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");
}
}
}
这一步是从订阅类中寻找带有注解的方法。先尝试 class.getDeclaredMethods()
,如果获取不到再尝试 class.getMethods()
。
getDeclaredMethods 不包含继承类方法,getMethods 包含。
fat classes like Activities 是亮点哈。
下面那么多嵌套,都是一些判断:是否修饰符为 public ,是否为非静态方法,是否方法传入参数个数为 1,该方法是否带有 @Subscribe 注解 …… 然后检查是否添加过。
java 代码解读复制代码
boolean checkAdd(Method method, Class> eventType) {
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
因为我们之前没有插入过方法,那么 existing == null
,return true,代表数据插入成功。
添加方法完成后,然后 new SubscriberMethod() ,并把对应参数都放入构造函数,最后由 findState.subscriberMethods
添加进列表当中。此时 findState 中就有部分数据了。
java 代码解读复制代码
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(
new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(),
subscribeAnnotation.sticky()));
}
接下来是 moveToSuperclass()
。
java 代码解读复制代码
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
之前在获取方法时,有两种情况。如果 getDeclaredMethods()
方法失败,那么就 getMethods()
,此时因为获取了所有方法,所以 skipSuperClasses 就设为 ture,因为已经不需要遍历父级。
假设我们之前走 getDeclaredMethods()
方法。此时将 findState 中的 clazz 变为父级的 Class ,如果是 java 的类或者 android 的类则跳过查找。while (findState.clazz != null)
满足条件,继续循环。
findState.subscriberInfo 从刚才的信息中没看出变化,所以仍然和刚才的循环一样,直到没有父类。最后调用 getMethodsAndRelease()
。
java 代码解读复制代码
private List getMethodsAndRelease(FindState findState) {
List 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;
}
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
最后把 *List < SubscriberMethod > * 进行返回,findState 通过 recycle()
重置了信息,放入 FIND_STATE_POOL 中。
java 代码解读复制代码
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)。如果有符合的方法,放入 METHOD_CACHE 中。
METHOD_CACHE 结构: Map < Class < 注册 > , List< SubscriberMethod >>
EventBus.register()
方法就分析了一半了,说多不多,说少不少,接着看另外半部分。
获取到了对应的信息,那么接下来就是分别注册了,使用 subscribe()
进行订阅,可能会出现多线程注册,所以带有 synchronized 关键字。
subscribe()
java 代码解读复制代码
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType;
//此时是将订阅对象 与 订阅方法组成一个新的数据结构,
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//subscriptionsByEventType 是以事件类型为键的 map,存入对应的 List。
CopyOnWriteArrayList 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);
}
}
//通过按优先级放入列表中,此时完成了 @Subscibe 中 priority 设定对应的处理。
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 是以 subscriber 为键,插入 List> 的结构, class> 为 消息事件的类。
List> 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).
Set, Object>> entries = stickyEvents.entrySet();
for (Map.Entry, 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);
}
}
}
中间 for 循环,subscriptions.add
时完成了对 @Subscribe.priority 的实现。
假设我们 subscribe
4 次,优先级分别为 0 , 20, 10, 0 。
- 第一次进来,size = 0 ; subscriptions 直接添加进入列表中。
- 第二次进来,size = 1 ; 20 优先级 与 subscriptions.get(0)(0 优先级)进行判断,i == 0 , size = 1 ;第一个条件不满足,20 > 10 满足条件,
subscriptions.add(0)
。此时列表中为 20 ,0。 - 第三次进来,size = 2 ; 10 优先级 与 subscriptions.get(0)(20 优先级)进行判断,i == 0 , size = 2 ;第一条件不满足,10 < 20 不满足条件,进行下一次判断。10 优先级 与 subscriptions.get(1) (0 优先级)判断 , i == 1 ,size = 2 ;第一条件不满足,10 > 0 满足条件,
subscriptions.add(1)
。此时列表中为 20 ,10 ,0。 - 第四次进来,size = 3 ;按照之前一样的分析,应该是 i = 3 , size = 3 时满足条件,那么就是放最后,此时列表为 20 , 10 , 0 , 0。
java 代码解读复制代码
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;
}
}
到此 register()
分析完成。接下来看 unregister()
。
unregister();
java 代码解读复制代码
public synchronized void unregister(Object subscriber) {
//这个列表是 <订阅对象,List<事件消息.class>> 的数据结构。
List> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
//此处传入 订阅对象 与 消息类型
for (Class> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
private void unsubscribeByEventType(Object subscriber, Class> eventType) {
//通过事件类型,拿到对应 Subscription ,此类是 保存 订阅对象 与 订阅方法的。
List subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
//挨着寻找是否有相同的订阅对象的 Subscription ,如果有则从中移除。
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
unregister()
比 register()
就简单多了,把加入列表的重新移除就行了。
remove()
之后,List 自动把元素向前移动了,所以此时 i 还是用原来的值,但是 size 需要减小。
那就只剩最后一步 post()
。
post()
java 代码解读复制代码
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List
eventQueue.add(event);
if (!postingState.isPosting) {
……
}
}
private final ThreadLocal currentPostingThreadState =
new ThreadLocal() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
final List
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}
currentPostingThreadState 为 ThreadLocal 类型,保存对于同一变量在不同线程状态下的信息。
从 PostingThreadState 的构造函数可以看出,除了 eventQueue 被初始化了,其他都是默认 false 或 null 值。
将 event 添加进列表后,接着看 if (!postingState.isPosting)
,因为第一次发消息,根据默认值 false ,满足条件。
java 代码解读复制代码
if (!postingState.isPosting) {
//对比当前现成的 looper 是否对应 mainLooper,如果是则为主线程,反之为非主线程。
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()) {
//尝试 eventQueue.isEmpty() 不为空时,remove 队列最前的消息,进行 postSingleEvent
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
//完成之后重新设置标志位。其实既然都是 threadlocal 变量了,感觉 isMainThread 没必要多次设置。
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
逻辑比较简单,注释中也说明了,然后看 postSingleEvent()
。
java 代码解读复制代码
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
//拿到对应消息时间的类
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
//构造函数中默认为 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);
}
//如果没有找到对应的 subscription 对象,那么进行一些发出消息的处理。
if (!subscriptionFound) {
//是否打印日志。
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
//这个操作比较亮,自己放入一个 NoSubscriberEvent 事件,可以通过在方法中增加对此事件的监听。
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
eventInheritance 的值可以从 EventBus 构造函数中得出,是 true 。如果是 true ,那么就是走上面, lookupAllEventTypes
。
java 代码解读复制代码
EventBus(EventBusBuilder builder) {
……
eventInheritance = builder.eventInheritance;
}
public class EventBusBuilder {
……
boolean eventInheritance = true;
EventBusBuilder() {}
}
/** Looks up all Class objects including super classes and interfaces.
Should also work for interfaces. */
private static List> lookupAllEventTypes(Class> eventClass) {
synchronized (eventTypesCache) {
List> eventTypes = eventTypesCache.get(eventClass);
if (eventTypes == null) {
eventTypes = new ArrayList<>();
Class> clazz = eventClass;
while (clazz != null) {
eventTypes.add(clazz);
addInterfaces(eventTypes, clazz.getInterfaces());
clazz = clazz.getSuperclass();
}
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}
从 lookupAllEventTypes
代码上来看,eventTypesCache 的结构是这样的。
Map < Class < 消息事件 > , List < Class <消息事件及其父类 >>> 。
当然我们自定义的一个消息类,clazz.getSuperclass()
为 Object ,所以这个列表实际上只有 eventClass 以及Obejct 类本身。并且我们单纯定义的消息事件类,并不实现任何接口,所以暂时不考虑 addInterfaces() 的逻辑。
那重点就是 postSingleEventForEventType()
,我们至此都没有看到消息时怎么处理的,ThreadMode 对应不同的值,也没有看到相关的逻辑。
java 代码解读复制代码
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class> eventClass) {
CopyOnWriteArrayList subscriptions;
//通过事件class 拿到对应的 subscription,就是 包含订阅对象与订阅方法的结构。
synchronized (this) {
//此处因为 Object 类没有放在 map 中,所以 get(Object.class) == null 直接返回false.
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
//如果拿到对应的 subscription 不为 null,则分别进行处理。
for (Subscription subscription : subscriptions) {
//此处 postingState.event 是方便后面如果需要 cancel。
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
//postingState.canceled 默认为 false,如果调用了 cancelEventDelivery ,则改为了 true。
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
//如果调用了 cancelEventDelivery ,则 aborted = true,中断后面的事件。
if (aborted) {
break;
}
}
return true;
}
return false;
}
仍然么有看到 ThreadMode 有关,还剩一个方法 postToSubscription()
。我们继续跟下去。
java 代码解读复制代码
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);
}
}
终于看到了这个,证明方向没错。
Thread.Mode_POSTING
java 代码解读复制代码
//POSTING
//方法很直接,拿到对应的方法,然后调用 invoke ,传入需要的对象以及 该消息事件。
//所以也对应了注释,直接在线程上调用,也是默认的 threadMode。
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);
}
}
//MAIN
//此处的 isMainThread 是 PostingState 中进行 looper 判断时,保存的值。
//如果是非主线程则需要 mainThreadPoster 进行处理.
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
//BACKGROUND
//和刚才的 Main 刚好相反,如果是非主线程,直接调用,主线程时,需要使用 backgroundPoster 进行处理。
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
//ASYNC
//这个是什么情况都由 asyncPoster 进行处理。
asyncPoster.enqueue(subscription, event);
那现在我们分析的重点就是 3 个 Poster,先来看 mainThreadPoster。
Thread.Mode_MAIN
java 代码解读复制代码
EventBus(EventBusBuilder builder) {
// 3 个poster都是在构造函数中初始化的。
//使用了 Looper.getMainLooper。
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
……
}
HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
先不看 HandlerPoster.enqueue() 方法,PendingPostQueue 看着不像是一个眼熟的类,像是 EventBus 自己定义的容器管理类,点开看看。
java 代码解读复制代码
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();
}
}
就是定义了一个链表的容器,加入了插入与取出的方法。那我们看回 HandlerPoster,先看 enqueue()
。
java 代码解读复制代码
//后弦是集成 Handler 的,所有可以发送消息和处理消息。
final class HandlerPoster extends Handler {
private boolean handlerActive;
void enqueue(Subscription subscription, Object event) {
//根据 subscription 与 event 组装一个 PendingPost。
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");
}
}
}
}
//从 pendingPostPool 进行复用,如果不够时再 new 一个新的。
static PendingPost obtainPendingPost(Subscription subscription, Object event) {
synchronized (pendingPostPool) {
int size = pendingPostPool.size();
if (size > 0) {
PendingPost pendingPost = pendingPostPool.remove(size - 1);
pendingPost.event = event;
pendingPost.subscription = subscription;
pendingPost.next = null;
return pendingPost;
}
}
return new PendingPost(event, subscription);
}
}
既然有 sendMessage()
,那么就有 handleMessage ()
方法。
java 代码解读复制代码
@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;
}
}
}
//此方法就是直接调用 method.invoke ,加入了对 PendingPost 的回收逻辑。
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 为 false。
handlerActive = rescheduled;
}
}
//对 invokeSubscriber() 进行调用;
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
//如果取消了订阅,那么 active 为 false。
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}
//PendingPost 的回收。
static void releasePendingPost(PendingPost pendingPost) {
pendingPost.event = null;
pendingPost.subscription = null;
pendingPost.next = null;
synchronized (pendingPostPool) {
// Don't let the pool grow indefinitely
if (pendingPostPool.size() < 10000) {
pendingPostPool.add(pendingPost);
}
}
}
稍微有点复杂的就是 maxMillisInsideHandleMessage 的理解,插入了消息事件,如果 Handler 没有处理完之前队列的消息,就超过了 maxMillisInsideHandleMessage ,则执行完此次任务后就会停止执行,发送新的消息再来执行。
直到所有事件执行完,handlerActive 才会改为 false,否则因为 rescheduled = true
,返回时 handlerActive 也一直为 true。
接下来看 BackgroundPoster.
Thread.Mode_BACKGROUND
java 代码解读复制代码 //和 handlerPoster 差不多。
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);
//此处用的线程池进行的执行,不过 executorRunning 与 handlerActive 差不多的意义,标记正在执行任务中。
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
try {
try {
while (true) {
//从 queue 中取出 PendingPost ,如果没有的话,返回并且标记任务执行完成。
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;
}
}
}
//和 HandlerPoster 一样,都是调用 eventBus.invokeSubscriber(pendingPost)
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
因为之前分析的 HandlerPoster 差不多的逻辑,唯一要看的就是 eventBus.getExecutorService()
是从哪来的。
java 代码解读复制代码
class EventBus{
ExecutorService getExecutorService() {
return executorService;
}
EventBus(EventBusBuilder builder) {
……
executorService = builder.executorService;
}
}
class EventBusBuilder{
……
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
}
可以看到是 Builder 中自带的 newCachedThreadPool 。那么 BackGroundPoster 也分析完成,只剩 AsyncPoster 。
Thread.Mode_ASYNC
java 代码解读复制代码
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);
}
}
和 BackgroundPoster 差不多,唯一区别就是 AsyncPoster 并没有加入标志位限制 execute()
的次数,只要来任务,就可以直接调用 execute()
,而 BackgroundPoster 做了一定的队列处理,保证了不会占用线程池过多资源。那么大体分析就差不多了。
下篇文章我们将接着看 EventBus 其他细节。从 EventBus 三个方法入手看源码(二)
此分析纯属个人见解,如果有不对之处或者欠妥地方,欢迎指出一起讨论。
评论记录:
回复评论: