看源码其实就和小时候拆玩具差不多,拆其实挺简单的,难的是拆了还能组合回来…
----沃兹基硕德
基本使用
使用的是EventBus-3.1.1
1.创建事件类,这里创建了LogEvent类,事件类理论上可以是任意对象,当然尽量命名规范予以区别
public class LogEvent {}
2.在某个类中注册事件,需要创建一个以事件为参数的方法,并且加以@Subscribe注解,@Subscribe有三个可选参数:
Subscribe参数 | 说明 |
---|---|
threadMode | 接收事件动作所在的线程,默认为ThreadMode.POSTING |
sticky | 是否粘性。指是否具有事件发布再注册也能接收事件的特殊功能,默认为false |
priority | 优先级。数值越大,在相同的线程下越先接收到事件,默认为0 |
threadMode类型 | 说明 |
---|---|
ThreadMode.POSTING | 与发布事件动作(post)所在的线程相同 |
ThreadMode.MAIN | 主线程,在Android中指UI线程 |
ThreadMode.MAIN_ORDERED | 主线程,总是可以顺序接收 |
ThreadMode.BACKGROUND | 后台线程,如果发布事件在主线程,则自建线程,反之与发布线程相同 |
ThreadMode.ASYNC | 异步线程,总是自建线程接收事件 |
public class MainActivity extends FragmentActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册
EventBus.getDefault().register(this);
}
//注册是必须的
@Subscribe(threadMode = ThreadMode.POSTING, sticky = false, priority = 0)
public void onMain(LogEvent event){
//填充逻辑
}
@Override
protected void onDestroy() {
//反注册
EventBus.getDefault().unregister(this);
super.onDestroy();
}
}
3.在某个类中调用post :
EventBus.getDefault().post(new LogEvent());
EventBus.getDefault().postSticky(new LogEvent());//sticky=true使用
完毕。
就是这么简单易用。
源码分析
按照调用习惯,先看一下getDefault()里面有什么吧:
//EventBus.java
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
static volatile EventBus defaultInstance;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
public EventBus() {
this(DEFAULT_BUILDER);
}
嗯,果然没什么好看的。就是个DCL的单例模式。
很久以前,我以为有getDefault()就会其他getSpecial()之类的,事实证明想多了…
需要注意一下的就是这里的volatile关键字,这是DCL单例中必备的一个关键字,复习一下:
1.保证了被修饰的变量对所有线程的可见性;
2.不能保证原子性,因与其修饰变量相关的写入操作无法保证原子性
推荐看看Java并发编程:volatile关键字解析
另外,注意一下这个EventBusBuilder,这里结合两个类看一下一些比较重要的属性:
//EventBus.java
EventBus(EventBusBuilder builder) {
//以Event为key的map
subscriptionsByEventType = new HashMap<>();
//以Subscriber为key的map
typesBySubscriber = new HashMap<>();
//粘性事件map
stickyEvents = new ConcurrentHashMap<>();
//判断是否为主线程的依据
mainThreadSupport = builder.getMainThreadSupport();
//用于寻找@Subscribe的方法
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
//是否考虑event的继承关系
eventInheritance = builder.eventInheritance;
//略过部分属性
}
//EventBusBuilder.java
public class EventBusBuilder {
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
//默认处理event的继承关系
boolean eventInheritance = true;
//默认为false
boolean ignoreGeneratedIndex;
//默认为无界线程池
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
//主线程相关类
MainThreadSupport mainThreadSupport;
//略过部分属性
EventBusBuilder() {
}
}
这些属性大概有个印象就行,中途会用到的还会回来看的,接下来看下register干了什么。
注册
//EventBus.java
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//找到当前订阅类注解Subscribe的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//遍历去建立当前订阅类与标记方法的映射关系
subscribe(subscriber, subscriberMethod);
}
}
}
这里看到就两个步骤,第一步是找到订阅类中所有注解过的方法,第二步是建立这些方法与订阅类的映射关系。
第一步.找到订阅类中所有注解过的方法
就之前的Demo来说,这里的subscriber就是MainActivity,看看里面subscriberMethodFinder.findSubscriberMethods做了什么事情吧:
//SubscriberMethodFinder.java
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
//找到与订阅类相关的方法,并封装为SubscriberMethod
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//默认为false
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
//为空代表着些订阅类并没有注解Subscribe的方法,抛出异常
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;
}
}
默认情况下进了findUsingInfo方法:
//SubscriberMethodFinder.java
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
private List<SubscriberMethod> 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();
}
//拿到List<SubscriberMethod>释放findState
return getMethodsAndRelease(findState);
}
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();
}
static class FindState {
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
//略过部分代码
}
这里的FindState不必太过在意,暂且当作一个类似缓存的东西存在好了,这里创建了一个长度为4的FindState数组作为缓存区,重点还是看findUsingReflectionInSingleClass做了什么:
//SubscriberMethodFinder.java
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
//尝试找到订阅类所有方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
//尝试找到订阅类所有public方法
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
//遍历方法,开始筛选目标
for (Method method : methods) {
int modifiers = method.getModifiers();
//只在Public方法中寻找,且不带abstract、static修饰
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) {
//拿到Event事件类型
Class<?> eventType = parameterTypes[0];
//首次订阅为true
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
//拿到threadMode、stciky、priority等参数,封装SubscriberMethod
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
//方法参数数量不是1个,抛出异常
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)) {
//方法修饰符不为单纯的public,抛出异常
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
这个方法就是通过反射在寻找合法的订阅接收事件的方法,这里的反射有两个地方需要注意一下,一是getDeclaredMethods和getMethods的区别,复习一下:
方法 | 说明 |
---|---|
getDeclaredMethods | 返回某个类的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。包括它所实现接口的方法。 |
getMethods | 返回某个类的所有公用(public)方法包括其继承类的公用方法,包括它所实现接口的方法。 |
二是类似(modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0的判断,可以通过得到方法的修饰符整数标记getModifiers和PUBLIC等整数常量进行位与(&)运算的结果是否非0的方式来判断方法的修饰符:
//SubscriberMethodFinder.java
private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;
//Modifier.java
public static final int PUBLIC = 0x00000001;
public static boolean isPublic(int mod) {
return (mod & PUBLIC) != 0;
}
话说回来,我们通过findUsingInfo拿到了SubscriberMethods,那么findUsingReflection呢?
//SubscriberMethodFinder.java
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
其实也是一样的:
//SubscriberMethodFinder.java
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//通过同样的方法拿到
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
最终通过getMethodsAndRelease方法将findState释放回收掉,返回了subscriberMethods。
//SubscriberMethodFinder.java
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;
}
就之前的demo来说,SubscriberMethods列表中应该只有一个元素,这个值封装的属性参照一下类:
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class<?> eventType;
final int priority;
final boolean sticky;
String methodString;
public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.priority = priority;
this.sticky = sticky;
}
}
那么demo中封装有SubscriberMethod各参数应该为:
类型 | 参数 | 值 |
---|---|---|
Method | method | onMain |
Class<?> | eventType | LogEvent |
ThreadMode | threadMode | ThreadMode.POSTING |
int | priority | 0 |
boolean | sticky | false |
现在注册的第一个步骤算是完成了,接下来就是建立映射关系了。
第二步.建立订阅方法与订阅类的映射关系
遍历所有的SubscriberMethod,与当前订阅类建立联系:
//EventBus.java
//以Event类型为键,以与Event相关的映射关系Subscription为值
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
//以订阅类为键,以订阅类可接收的Event列表为值
private final Map<Object, List<Class<?>>> typesBySubscriber;
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
//封装了Subscription
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
//首次订阅第一个Event为空
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);
}
}
//此处是实现priority的关键,总体就是间接为subscriptions通过priority排了序
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
//只有priority比当前subscriberMethod方法更大时,才能插队,否则依次插入列表尾部
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
//添加订阅类与event的映射关系
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//处理sticky=true的情况,如果sticky=false,注册到这里就算完毕了
if (subscriberMethod.sticky) {
//默认为true,默认处理event继承关系
if (eventInheritance) {
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);
}
}
}
可以看到subscribe中已经完成了与priority、sticky相关逻辑,
对priority,是采用了间接对subscriptions排序,在这里完全可以推测出后面的post逻辑应该在遍历subscriptions列表调用了通过反射得出的订阅方法,这里的顺序就体现出了priority的作用;
对sticky,是当前就调用了checkPostStickyEventToSubscription方法,这里也可以推测这个方法应该实现了对订阅方法的调用;
就demo来说,
newSubscription = Subscription(MainActvity,subscriberMethod(onMain,LogEvent,ThreadMode.POSTING,0,false)
typesBySubscriber = Map(MainActivity,List[LogEvent.class])
subscriptionsByEventType = Map(LogEvent.class,CopyOnWriteArrayList[newSubscription])
stickyEvents = Map()//如果有,则为Map(LogEvent.class,
来看看checkPostStickyEventToSubscription做了什么吧:
//EventBus.java
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
postToSubscription(newSubscription, stickyEvent, isMainThread());
}
}
调用了postToSubscription,这里已经接近终点了:
//EventBus.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 MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
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用各种poster实现了对线程的切换。
看到了invoke,就知道这里应该就是调用订阅方法的地方了:
//EventBus.java
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);
}
}
……
……
索然无味。
就是一个反射引用invoke,可以想见,正常的post流程最终也会走到这里。
这里的sticky之所以可以先postSticky再register也可以,是因为就代码本身来说,流程依然是在register时才真正post了,因此实现了”粘性“,使得register和postSticky可以颠倒顺序。
至此,register的逻辑就完毕了,现在来看一下post吧,来看看是否与猜想中一样呢。
发布
//EventBus.java
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
//判断是否为主线程
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);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
此处PostingThreadState和之前的FindState类似,看作一种过渡缓存就行了。
这里有一个比较有意思的地方,isMainThread,因为大家知道EventBus并不是只能用在Android中,这个判断是很有必要的,那么里面写了什么?
//EventBus.java
private boolean isMainThread() {
return mainThreadSupport != null ? mainThreadSupport.isMainThread() : true;
}
//MainThreadSupport.java
public interface MainThreadSupport {
boolean isMainThread();
Poster createPoster(EventBus eventBus);
class AndroidHandlerMainThreadSupport implements MainThreadSupport {
private final Looper looper;
public AndroidHandlerMainThreadSupport(Looper looper) {
this.looper = looper;
}
@Override
public boolean isMainThread() {
return looper == Looper.myLooper();
}
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
}
}
这里自己实现了一个类AndroidHandlerMainThreadSupport,判断的方法是looper == Looper.myLooper(),即判断当前的looper是否与当前myLooper返回的Looper相同。
可以相见,AndroidHandlerMainThreadSupport的构造参数,肯定传进了Looper.getMainLooper(),这个得从很久以前的EventBusBuilder说起了,当时不是传进了一个getMainThreadSupport么?
MainThreadSupport getMainThreadSupport() {
if (mainThreadSupport != null) {
return mainThreadSupport;
} else if (Logger.AndroidLogger.isAndroidLogAvailable()) {
Object looperOrNull = getAndroidMainLooperOrNull();
return looperOrNull == null ? null :
new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
} else {
return null;
}
}
这里!
在判断是AndroidLog是否可用?wtf?
//Logger.java
public interface Logger {
void log(Level level, String msg);
void log(Level level, String msg, Throwable th);
public static class AndroidLogger implements Logger {
static final boolean ANDROID_LOG_AVAILABLE;
static {
boolean android = false;
try {
//6666666
android = Class.forName("android.util.Log") != null;
} catch (ClassNotFoundException e) {
// OK
}
ANDROID_LOG_AVAILABLE = android;
}
public static boolean isAndroidLogAvailable() {
return ANDROID_LOG_AVAILABLE;
}
}
}
没有错。
这里居然在判断当前系统是不是Android?并且使用的是寻找"android.util.Log"类,找得到?好,这就是安卓了!
如果以后google突发其想把这个类给删除了,会不会让EventBus怨念深重…
当前是Android系统就好办啦,反手就是一个getMainLooper:
//EventBusBuilder.java
Object getAndroidMainLooperOrNull() {
try {
return Looper.getMainLooper();
} catch (RuntimeException e) {
return null;
}
}
回到正题,post中加入了是否为主线程的判断,然后执行了postSingleEvent:
//EventBus.java
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
//找到所有与Event相关的父类、接口等
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) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
注意一下,这里的lookupAllEventTypes会找到其父类,直到找到Object为止,包括Object.class。
结合demo,此时
eventTypes = List[LogEvent.class,Object.class]
subscriptionsByEventType = Map(LogEvent.class,CopyOnWriteArrayList[newSubscription])
来吧,都通过postSingleEventForEventType发出去吧:
//EventBus.java
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
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;
}
这里的subscriptionsByEventType.get(Object.class)在一般情况下肯定是没有值的,所以可以当作一个终止标记,这也是使用subscriptionFound |= postSingleEventForEventType(…)的原因所在,两者配合就达到了遍历所有上层类,直到没有映射关系的时候终止发送,一般情况下到超类Object.class就为止了。
最终和之前的sticky事件一样,来到了postToSubscription,然后调用invokeSubscriber。
没有任何悬念。
那么粘性事件专用的postSticky呢?
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
post(event);
}
同样走的post流程,只是在走之前将事件存入了stickyEvents中,这里就可以与之前register中的subscribe对应起来,只有调用postSticky时,stickyEvents才会有值。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//略过部分代码
if (subscriberMethod.sticky) {
if (eventInheritance) {
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);
}
}
}
对应demo,此时
stickyEvents = Map(LogEvent.class,List[LogEvent])
至于postToSubscription中的各种Poster,都是与queue、线程池相关的东西,有兴趣可以探究一下。
比如在threadMode==ThreadMode.ASYNC时,
//EventBus.java
private final AsyncPoster asyncPoster;
EventBus(EventBusBuilder builder) {
//略过部分代码
asyncPoster = new AsyncPoster(this);
//略过部分代码
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
//略过部分代码
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
}
}
asyncPoster本身就集成了序列与线程的作用,
class AsyncPoster implements Runnable, Poster {
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);
}
}
其他非主线程的调用都大同小异,问题不大。
反注册
这个步骤自然是清除各种缓存,重置标记。
//EventBus.java
//以Event类型为键,以与Event相关的映射关系Subscription为值
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
//以订阅类为键,以订阅类可接收的Event列表为值
private final Map<Object, List<Class<?>>> typesBySubscriber;
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
整个流程就这样了。
以上。