EventBus源码解析
EventBus github:https://github.com/greenrobot/EventBus
我自己fork了EventBus的github,并在master分支的EventBus的module写了注释,可以看一看:https://github.com/nanjolnoSat/EventBus
本博客是基于EventBus3.2.0版本编写的,不同版本的代码可能有所不同。
目录
如何使用
方法分析
其他代码
个人推荐用法
后记
如何使用
先从如何使用EventBus开始,再分析每个步骤的代码。注册
Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle:
注册和取消注册您的订阅者。例如在Android中的Activity和Fragment通常根据其生命周期进行注册。
@Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { super.onStop(); EventBus.getDefault().unregister(this); }
Define events
public static class MessageEvent { /* Additional fields if needed */ }
Prepare subscribers: Declare and annotate your subscribing method, optionally specify a thread mode:
准备订阅者,声明订阅方法并使用注解,也可以指定线程模式
@Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { /* Do something */};
发送消息
post events:
EventBus.getDefault().post(new MessageEvent());
方法分析
getDefault
register
postSticky和register的结合
SubscriberMethodFinder.findSubscriberMethods()
自定义SubscriberInfoIndex
unregister
post
线程切换
getDefault
这是一个双检索获取实例的方式,没什么好说的,看构造方法的代码。
Builder是一个静态常量。
关于EventBusBuilder,可以看org.greenrobot.eventbus.EventBusBuilder
再看看 EventBus(EventBusBuilder builder) 这个构造方法
//Event类型:即接收方法的参数类型EventBus(EventBusBuilder builder) { //用于打印日志 logger = builder.getLogger(); //Key为Class<?>,存储Event类型。Value为CopyOnWriteArrayList,存储方法信息列表。 //在register方法会将订阅者的方法存起来,在unregister会移除 //当调用post方法接收到通知之后,就根据Event类型获取到方法信息列表,再使用反射调用方法。 subscriptionsByEventType = new HashMap<>(); //Key为Object,存储订阅者。Value为List,存储该订阅者所有的Event类型。 //主要用于在调用unregister方法之后,从subscriptionsByEventType中移除相应的数据。 typesBySubscriber = new HashMap<>(); //Key为Class<?>,表示Event的类型。Value为Object,表示Event本身。 //sticky用百度翻译出来是 粘性的。直接说作用吧,不知道怎么翻译比较好。 //假设在启动某个Activity之前postSticky了一个 Event 对象,在启动一个新的Activity并register过程中 //该Activity的某个订阅方法的sticky为true,并且该方法接收的对象是 Event //那调用register过程中就会调用该订阅方法 //具体留到下面分析register方法的时候通过源码说明清楚。 stickyEvents = new ConcurrentHashMap<>(); //下面这几个都和线程相关的,先不讲,后面线程切换再统一讲。 mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); //indexCount没什么用,只用在toString()方法里面。重要的是builder里面的subscriberInfoIndexes //留到下面的Finder说明清楚,因为这个和Finder的关系比较大。 indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; //重要!!!EventBus内部通过订阅者找到订阅方法就是通过该对象进行查找。 //以下内容可以留到下面的Finder解析再看,这里可以不看,这里只是简单介绍。 //可以看到,这里在声明的时候传递了builder.subscriberInfoIndexes //这里先简单介绍subscriberInfoIndexes的作用,后面再通过源码详细介绍。 //在介绍subscriberInfoIndexes之前 //有一件事需要先说明,EventBus扫描一个类里面有哪些方法有两种方式。 //一种是使用反射,遍历所有方法,找到符合规定的方法。而另一种,就是使用subscriberInfoIndexes。 //要设置subscriberInfoIndexes的值,只能手动创建EventBus //EventBus内部提供了build()方法来作为建造者模式创建。 //在build方法里面有一个方法addIndex //需要传递一个SubscriberInfoIndex对象,而该对象最终获取到的是 //一个SubscriberInfo对象,该对象有几个方法,需要返回订阅者和订阅方法。 //所以这种方式和反射类似,只不过从性能的角度分析,这种方式性能更好,因为反射是需要遍历所有方法。 //而这种方式直接将需要的方法告诉EventBus。但这种方式写起来太麻烦了 //就我个人而言,如果不是对性能造成严重的影响或者对性能有比较高的要求,我是不会这样写的 subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex);//当invoke方法的时候,是否通过logger打印出来,默认为true。 logSubscriberExceptions = builder.logSubscriberExceptions; //当一个Event没有找到订阅对象的时候,是否通过logger打印出来,默认为true logNoSubscriberMessages = builder.logNoSubscriberMessages; //当invoke方法的时候,出现InvocationTargetException且不是SubscriberExceptionEvent //是否post一个SubscriberExceptionEvent事件,默认为true sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; //当一个Event没有找到订阅对象的时候,是否通过post一个NoSubscriberEvent事件,默认为true sendNoSubscriberEvent = builder.sendNoSubscriberEvent; //当invoke方法的时候,出现InvocationTargetException且不是SubscriberExceptionEvent //是否抛出异常,默认为false throwSubscriberException = builder.throwSubscriberException; //事件继承。 //下面这段话可以不看,实际上看了也没什么意义,因为有可能看完就忘了,留到后面再回过头过来看 //对于register的subscribe方法,如果为true。则只要上面的stickyEvents存在订阅方法的Event相同的类或者 //子类就会调用订阅方法 //对于post方法,如果为true,在post一个事件的时候,会找到该Event的所有Interface和父类 //然后将这些类都post出去 //默认为true eventInheritance = builder.eventInheritance; //线程池,ThreadMode为BACKGROUND和ASYNC最终都会交给该线程池执行 executorService = builder.executorService;}
关于构造方法的内容到此为止,通过分析构造方法每个字段的作用,就已经将EventBus的成员变量分析得差不多了。
register
先看一下方法文档及签名注册给定订阅服务器以接收事件,一旦订阅者不想接收事件,必须调用 unregister(Object)。
订阅者的处理方法必须使用Suubscribe注解。Subscribe注解还允许像 ThreadMode 和 priority(优先级) 这样的配置。
接下来对代码进行分析
Class<?> subscriberClass = subscriber.getClass();//这里代码比较复杂,先放一边,直接说结论。//调用这个方法之后,就能找到订阅者所有符合要求的方法,并获取到这些方法必要的信息,//存储到SubscriberMethod里面,并返回一个SubscriberMethod的List。List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); }}
SubsscriberMethod.java
/** Used internally by EventBus and generated subscriber indexes. */public class SubscriberMethod { //调用的方法 final Method method; //线程模式,留到post的时候再说 final ThreadMode threadMode; final Class<?> eventType; //优先级,默认为0 final int priority; //百度翻译:粘性的。默认为false。 final boolean sticky; /** Used for efficient comparison */ 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; }//重要,当比较两个方法是否相同的时候会用到。 @Override public boolean equals(Object other) { if (other == this) { return true; } else if (other instanceof SubscriberMethod) { checkMethodString(); SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other; otherSubscriberMethod.checkMethodString(); // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6 return methodString.equals(otherSubscriberMethod.methodString); } else { return false; } }//当两个对象不相同的时候,就通过:调用者的全限定名、方法名称、参数的权限定名。判断两个对象是否一致。 private synchronized void checkMethodString() { if (methodString == null) { // Method.toString has more overhead, just take relevant parts of the method StringBuilder builder = new StringBuilder(64); builder.append(method.getDeclaringClass().getName()); builder.append('#').append(method.getName()); builder.append('(').append(eventType.getName()); methodString = builder.toString(); } } @Override public int hashCode() { return method.hashCode(); }}
EventBus.subscribe(Object, SubscriberMethod)
// Must be called in synchronized block//必须在同步代码块里面调用private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { //Tag1 Class<?> eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); 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); } } //Tag2 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; } }//Tag3 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType);//Tag4 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<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); } }}
Tag1: 校验订阅者和订阅方法
先看Subscription的代码
final class Subscription { //订阅者 final Object subscriber; //subscribe传递过来的SubscriberMethod对象 final SubscriberMethod subscriberMethod; /** * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions. */ volatile boolean active; Subscription(Object subscriber, SubscriberMethod subscriberMethod) { this.subscriber = subscriber; this.subscriberMethod = subscriberMethod; active = true; }//equals是一个重要的方法,因为Tag1的代码有一处会判断是否存在Subscription对象//而判断的代码最终会调用equals方法 @Override public boolean equals(Object other) { if (other instanceof Subscription) { Subscription otherSubscription = (Subscription) other; //判断两个对象的订阅者是否一致,并且SubscriberMethod是否一致,这个具体查看SubscriberMethod的equals方法 return subscriber == otherSubscription.subscriber && subscriberMethod.equals(otherSubscription.subscriberMethod); } else { return false; } } @Override public int hashCode() { return subscriber.hashCode() + subscriberMethod.methodString.hashCode(); }}
再看一下剩下的代码
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); }}
还记得构造方法的subscriptionsByEventType字段吗,该字段就是在这里开始发挥作用的。
取出之后如果为空,表示第一次进来,所以new一个List,并put进去。
如果不为空,就判断是否存在,如果存在则表明存在:订阅者、方法所在类、订阅方法名称、Event类型完全一致的方法,这个时候可以说明这两个方法完全相同,是多余的,所以抛异常。
如果不存在,则进入Tag2。
Tag2: 将订阅方法插入到合适的位置
int size = subscriptions.size();//遍历subscriptions,这里看到结束的条件为i<=size//看起来好像会出现溢出一样,这里往下看就能知道为什么这样做了。for (int i = 0; i <= size; i++) { //先看后半段的判断,根据方法执行的优先级将方法插入到合适的位置//在i=size之前,也就是说遍历了整个subscriptions都没找到合适的位置//就将订阅方法插入到subscriptions的末尾 if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; }}
Tag3: 将订阅者作为key,Event类型的Class列表作为Value存起来。
这里只是做一个存储操作,然后当调用unregister方法的时候,typesBySubscriber就会发挥出它的作用。
Tag4: 如果订阅方法的sticky为true,就会执行下面的代码
//在构造方法已经对这个字段解释过了,这里再根据源码解释一次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<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); //遍历stickyEvents里面的数据,stickyEvents这个字段数据会在调用postSticky方法之后新增数据 for (Map.Entry<Class<?>, Object> entry : entries) { Class<?> candidateEventType = entry.getKey(); //当订阅方法的Event和遍历到的Event相同或者是父类,就会post。 if (eventType.isAssignableFrom(candidateEventType)) { Object stickyEvent = entry.getValue(); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } }} else { Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent);}
checkPostStickyEventToSubscription
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, isMainThread()); }}
postToSubscription方法就不讲了,留到后面post的时候再提。只要知道,调用这个方法之后,就和调用post的效果一样。
在调用register之前,调用了postSticky方法,并且在调用register的时候,存在相同Event的方法且该方法的sticky为true,就会调用这个方法。
postSticky和register的结合
结合上面的代码写一个测试代码先看postSticky的代码
/** * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}. */public void postSticky(Object event) { synchronized (stickyEvents) { stickyEvents.put(event.getClass(), event); } // Should be posted after it is putted, in case the subscriber wants to remove immediately post(event);}
从这里可以看得出,当使用postSticky方法之后,会将Event的Class和Event put 到stickyEvents里面。
EBMessage
class EBMessage
EBTest1Activity
class EBTest1Activity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_ebtest1) start_btn.setOnClickListener { EventBus.getDefault().postSticky(EBMessage()) startActivity(Intent(this, EBTest2Activity::class.java)) } }}
layout文件的代码就不贴了,就一个Button。
EBTest2Activity
class EBTest2Activity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_ebtest2) EventBus.getDefault().register(this) } @Subscribe(sticky = true) fun stickyTest(message: EBMessage) { Log.d("EBTest2Activity", "stickyTest") } override fun onDestroy() { super.onDestroy() EventBus.getDefault().unregister(this) }}
从上面的代码可以看到,启动EBTest2Activity之前会调用postSticky。在EBTest2Activity里面会注册EventBus,并且stickyTest的sticky的属性为true。从上面分析register源码可知,这种情况下,只要不出意外,就会执行stickyTest里面的代码。实际运行的时候确实也执行了。
SubscriberMethodFinder.findSubscriberMethods()
从register方法可知,该方法是将一个订阅者里面符合规则的所有方法都找出来。先看SubscriberMethodFinder的构造方法
SubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification, boolean ignoreGeneratedIndex) { //在EventBus里面用了很多句话描述了这个字段的作用,这里再简单描述 //当该对象不为空且ignoreGeneratedIndex为false的时候就不会通过反射的方式去扫描符合规则的方法 //而是直接使用这个列表提供的方法,至于为什么可以这样做, 看代码分析 this.subscriberInfoIndexes = subscriberInfoIndexes; //当使用反射遍历到的放大不符合规则的时候,且该变量为true,直接抛出EventBusException //默认为false this.strictMethodVerification = strictMethodVerification; //默认为false this.ignoreGeneratedIndex = ignoreGeneratedIndex;}
SubscriberInfoIndex
/** * Interface for generated indexes. */public interface SubscriberInfoIndex { //根据传递进来的Class返回合适的SubscriberInfo SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);}
SubscriberInfo
/** Base class for generated index classes created by annotation processing. */public interface SubscriberInfo { //如果是其他SubscriberInfo的父,即存在某个SubscriberInfo的getSuperSubscriberInfo()返回该SubscriberInfo对象 //这种情况下该方法返回的对象才能起到作用,这种情况下必须和getSubscriberMethods()里面Class.getMethod的Class //是同一个对象,如果不清楚会不会被其他SubscriberInfo.getSuperSubscriberInfo()引用,那就别返回空吧 //如果可以确定不被引用,那就可以偷懒,返回null Class<?> getSubscriberClass();//方法列表,即上面的SubscriberMethod对象 SubscriberMethod[] getSubscriberMethods();//如果不为空,就判断register方法传递过来的订阅者和该类的订阅者的Class对象是否一致//如果一致,这个留到findUsingInfo方法吧,这里讲了也没什么意义 SubscriberInfo getSuperSubscriberInfo();//在EventBus没有找到对该方法的使用,所以不清楚该方法的实际作用 boolean shouldCheckSuperclass();}
findSubscriberMethods
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { //Tag1 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; }//Tag2 if (ignoreGeneratedIndex) { //Tag3 subscriberMethods = findUsingReflection(subscriberClass); } else { //Tag4 subscriberMethods = findUsingInfo(subscriberClass); } //Tag5 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; }}
Tag1: 如果订阅者不是第一次调用这个方法,则存在缓存。因此,直接从缓存中取出数据并返回。
Tag2: 如果为true,就使用反射获取方法,为false使用findUsingInfo方法。在该方法内部会根据实际情况使用反射或者subscriberInfoIndexes。
Tag3: 使用反射找到订阅方法,这里的实现和Tag4的部分代码类似,所以就简单讲一下,具体再在Tag4讲清楚。
prepareFindState,从FindState池里面取出缓存,如果没有,就new一个。
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();}
initForSubscriber,为FindState赋上初始值
void initForSubscriber(Class<?> subscriberClass) { this.subscriberClass = clazz = subscriberClass; skipSuperClasses = false; subscriberInfo = null;}
findUsingReflection方法剩下的代码:
findUsingReflectionInSingleClass(findState):找到所有订阅方法,并存入FindState里面。
findState.moveToSuperclass():如果skipSuperClasses为false,就尝试从订阅者的父Class找订阅方法。
getMethodsAndRelease(findState):返回List
Tag4: 如果subscriberInfoIndexes不为空,就在这里面获取相应的数据。如果为空,就是使用反射。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); //只要findState的clazz字段不为空,循环就不会停止 while (findState.clazz != null) { //从FindState里面的subscriberInfo或者当前Finder的subscriberInfoIndexes找到SubscriberInfo对象。 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(); } //返回并缓存FindState对象 return getMethodsAndRelease(findState);}
FindState
static class FindState { //存储订阅方法,找到订阅方法之后会存储到这边来 final List<SubscriberMethod> subscriberMethods = new ArrayList<>();//下面这3个字段是校验相关的,都在FindState里面调用,下面遇到的时候再讲清楚 final Map<Class, Object> anyMethodByEventType = new HashMap<>(); final Map<String, Class> subscriberClassByMethodKey = new HashMap<>(); final StringBuilder methodKeyBuilder = new StringBuilder(128); //订阅者的Class对象 Class<?> subscriberClass; //由于当skipSuperClasses为false的时候,会不断从父类中查到订阅方法 //所以不能使用subscriberClass字段来找,所以单独用一个字段来存储要找的Class对象 Class<?> clazz; boolean skipSuperClasses; //存储订阅方法的信息 SubscriberInfo subscriberInfo; //初始化,先说明一下,之所以初始化的时候不调用recycle方法 //是因为在find完成之后,会调用recycle方法,并缓存到FindState池里面 //这个等下分析find方法的时候会提到 void initForSubscriber(Class<?> subscriberClass) { this.subscriberClass = clazz = subscriberClass; skipSuperClasses = false; subscriberInfo = null; }//回收操作void recycle() { subscriberMethods.clear(); anyMethodByEventType.clear(); subscriberClassByMethodKey.clear(); methodKeyBuilder.setLength(0); subscriberClass = null; clazz = null; skipSuperClasses = false; subscriberInfo = null; }//在订阅方法add之前,做一次校验返回true表示可以add。//随便找了一段代码,这是参数传递//findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType) boolean checkAdd(Method method, Class<?> eventType) { // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required. // Usually a subscriber doesn't have methods listening to the same event type. // 2级检查:第一级仅使用事件类型,第二级需要时使用完整签名。// 通常,一个订阅者不会监听相同Event的方法//final Map anyMethodByEventType = new HashMap<>(); Object existing = anyMethodByEventType.put(eventType, method); //当为null的时候,表示该Event只有一个方法 if (existing == null) { return true; } else { //执行到这里表示有两个方法及以上在监听同一个Event //这if里面的内容就是校验方法签名,如果叫校验通过,就将当前FindState put进去 //所以在第三次执行的时候,exitsting就不是Method对象,而是FindState //说实话,看不懂为什么要这样写,水平不足 //只是可以明白一个作用,那就是这样做了之后,就减少一次校验操作 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); } } private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) { //final StringBuilder methodKeyBuilder = new StringBuilder(128); //从这里可以看到methodKeyBuilder使用成员变量是起到一个缓存的作用,这样就不用频繁new StringBuilder methodKeyBuilder.setLength(0); //append之后会将StringBuilder作为Key,所以需要记住 //这个key包含Method的name和Event的name methodKeyBuilder.append(method.getName()); methodKeyBuilder.append('>').append(eventType.getName()); String methodKey = methodKeyBuilder.toString(); Class<?> methodClass = method.getDeclaringClass(); //final Map subscriberClassByMethodKey = new HashMap<>(); Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); //当该Method上次所在的类是这次所在的类的本身或者是父类,就没问题 //这样做其实是有原因的,这里回到上面的checkAdd方法,来分析为什么要进入这个方法校验一次 //在checkAdd里面发现了有两个方法在监听同一个Event,按照EventBus的文档说明,可以看出 //EventBus的开发人员认为一般情况下不会存在两个方法监听同一个Event //但为了防止出现这总情况,只要合法就允许这样做 //那什么情况下是合法呢 //1,方法名称不一样:只要方法名称不一样,那StringBuilder拼接出来的key也就不一样,所以methodClassOld肯定为空,返回true //2,这个方法是父类的一个方法:只要是父类的方法,那名称一样也没问题 //不过根据我实际测试,不清楚是EventBus没想到这个问题,还是其他原因 //我使用addIndex这种方式,添加两个完全一样的方法,在register的subscribe的时候直接抛出异常 //也就是说这种场景下,也会将这个方法添加到方法列表,并不会过滤掉完全相同的方法 if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { // Only add if not already found in a sub class return true; } else { // Revert the put, old class is further down the class hierarchy // 否则就恢复现场 subscriberClassByMethodKey.put(methodKey, methodClassOld); return false; } } //如果有父类,并且不忽略父类,就将clazz设置为父类 void moveToSuperclass() { if (skipSuperClasses) { clazz = null; } else { clazz = clazz.getSuperclass(); String clazzName = clazz.getName(); // Skip system classes, this degrades performance. // Also we might avoid some ClassNotFoundException (see FAQ for background). // 这里的注释的意思其实也很明确了,跳过java核心库和android核心库 if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.") || clazzName.startsWith("androidx.")) { clazz = null; } } }}
FindState讲完了,回到 findUsingInfo 这方法本身
while循环: while循环的结束条件是clazz == null,对于该方法来说,其实就当找不到合适的父类的时候就会跳出循环。所以每次执行完所有代码之后都会调用一次 findState.moveToSuperclass(),这个刚才也讲过了,这里就不讲了。
获取SubscriberInfo
findState.subscriberInfo = getSubscriberInfo(findState);private SubscriberInfo getSubscriberInfo(FindState findState) { //这一段可以先不看,因为第一次执行的时候一定为null,可以先看下面再回头看这里//下面那段代码获取到SubscriberInfo之后,在while循环里面获取到Class对象之后就会第二次执行这里//这个时候findState.subscriberInfo就有可能不为空,当不为空,且存在父SubscriberInfo//并且父SubscriberInfo的订阅类和clazz一样,就返回 if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) { SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo(); if (findState.clazz == superclassInfo.getSubscriberClass()) { return superclassInfo; } }//Finder的indexes不为空,这个就是构造方法接收的那个List if (subscriberInfoIndexes != null) { for (SubscriberInfoIndex index : subscriberInfoIndexes) { //会传递Class对象获取到对应的SubscriberInfo,当获取到属于该类的SubscriberInfo,就返回 SubscriberInfo info = index.getSubscriberInfo(findState.clazz); if (info != null) { return info; } } } return null;}
当获取SubscriberInfo之后不为空,就执行下面的代码
//调用getSubscriberMethods获取到订阅方法列表,并遍历SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();for (SubscriberMethod subscriberMethod : array) { //对订阅方法校验,从上面的checkAdd的代码可知,并没有检查该方法是否存在Subscribe注解//所以这种方式返回的方法,是不需要该注解的 if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); }}
如果为空,就调用findUsingReflectionInSingleClass
//通过反射的方法寻找订阅方法private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; //获取方法列表,当使用getDeclaredMethods获取失败的时候,就使用getMethods获取 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 try { methods = findState.clazz.getMethods(); } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad... String msg = "Could not inspect methods of " + findState.clazz.getName(); if (ignoreGeneratedIndex) { msg += ". Please consider using EventBus annotation processor to avoid reflection."; } else { msg += ". Please make this class visible to EventBus annotation processor to avoid reflection."; } throw new EventBusException(msg, error); } 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) { //下面就是对方法的校验和SubscriberMethod的封装,没什么难度,就不做过多说明了 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())); } } //不符合上面的if,有Subscribe这个注解,就抛出异常 } 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); } //不符合上面的if,有Subscribe这个注解,就抛出异常 } 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"); } }}
getMethodsAndRelease方法
//当while执行完成之后,就会执行这里private List<SubscriberMethod> getMethodsAndRelease(FindState findState) { //创建一个新的List,用于返回。这里其实就是将findState的subscriberMethods克隆出来。 List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods); //FindState做回收操作,并放入FindState池里面,供下次使用 //从这里也可以看到,为什么从FindState池里面取出数据之后不用清空里面的数据 //因为在放入池之前就已经做了回收操作 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;}
Tag5: 当最后找到的subscriberMethods为空,就说明没有需要接收订阅事件的方法。既然不存在需要接收订阅事件的方法,那干嘛要注册,所以就直接抛出异常了。
而如果存在,就将该对象放入缓存,下次进来的时候就不用执行find操作。
clearCaches(): 这个方法是Finder唯一一个没有提到的方法,其实从名称也可以看出,就是清除缓存
static void clearCaches() { METHOD_CACHE.clear();}
自定义SubscriberInfoIndex
从上面对Finder的分析也清楚了SubscriberInfoIndex的用法,所以这里通过一个demo复习一下初始化EventBus的时候需要做很多操作所以这里是直接在Application里面对EventBus初始化
EBApplication
class EBApplication : Application() { val eventBus: EventBus = EventBus.builder() .addIndex(EBTestSIIndex()) .build() companion object { private var instance: EBApplication? = null fun getInstance() = instance!! } override fun onCreate() { super.onCreate() instance = this }}
EBTestSIIndex
class EBTestSIIndex : SubscriberInfoIndex { override fun getSubscriberInfo(subscriberClass: Class<*>?): SubscriberInfo? { //只有是EBTestActivity这个类才会返回该SubscriberInfo,其他情况返回null if (subscriberClass == EBTestActivity::class.java) { val info = object : SubscriberInfo { //从源码中可以看到,只有该SubscriberInfo是其他SubscriberInfo的SuperSubscriberInfo //的时候,才会调用这个方法,这里的demo只是一个简单的SubscriberInfo,所以可以直接返回null override fun getSubscriberClass(): Class<*>? = null override fun getSubscriberMethods(): Array<SubscriberMethod> { val clazz = EBTestActivity::class.java val eventType = EBMessage::class.java val method1 = clazz.getMethod("ebTest1_1Subscribe", eventType) val method2 = clazz.getMethod("ebTest1_2Subscribe", eventType) return arrayOf( SubscriberMethod(method1, eventType, ThreadMode.MAIN, 0, false), SubscriberMethod(method2, eventType, ThreadMode.MAIN, 0, false) ) } //如果不需要Super,就返回空 override fun getSuperSubscriberInfo(): SubscriberInfo? = null override fun shouldCheckSuperclass(): Boolean = false } return info } else { return null } }}
EBTestActivity
class EBTestActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_eb_test) EBApplication.getInstance().eventBus.register(this) post_btn.setOnClickListener { EBApplication.getInstance().eventBus.post(EBMessage()) } } fun ebTest1_1Subscribe(event: EBMessage) { Log.d("EBTestActivity", "ebTest1_1Subscribe") } fun ebTest1_2Subscribe(event: EBMessage) { Log.d("EBTestActivity", "ebTest1_2Subscribe") } override fun onDestroy() { super.onDestroy() EBApplication.getInstance().eventBus.unregister(this) }}
通过测试发现,点击poost之后可以打印出两句log,所以想法没问题。
再来一个反例
EBTest2Activity,直接将EBTestActivity的两个方法复制过来,会发现在register的时候出现了问题
这也证明了在EBTestSIIndex里面的 if (subscriberClass == EBTestActivity::class.java) 的判断是起到作用的
class EBTest2Activity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_ebtest2) EBApplication.getInstance().eventBus.register(this) } fun ebTest1_1Subscribe(event: EBMessage) { Log.d("EBTestActivity", "ebTest1_1Subscribe") } fun ebTest1_2Subscribe(event: EBMessage) { Log.d("EBTestActivity", "ebTest1_2Subscribe") } override fun onDestroy() { super.onDestroy() EBApplication.getInstance().eventBus.unregister(this) }}
unregister
取消注册/** Unregisters the given subscriber from all event classes. */// 将订阅者所有的事件的Class取消注册public synchronized void unregister(Object subscriber) { //这个字段就是在register里面保存事件的,在取消注册的时候就发挥出它的作用//这里取出订阅者所有的事件,并根据事件的Class清理相应的方法 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()); }}
unsubscribeByEventType
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { //通过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--; } } }}
post
在介绍post方法之前,先把post里面一些需要用到的代码讲清楚currentPostingThreadState,使用ThreadLocal保证一个线程只有PostingThreadState对象
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); }};
PostingThreadState
/** For ThreadLocal, much faster to set (and get multiple values). */final static class PostingThreadState { //Event队列 final List<Object> eventQueue = new ArrayList<>(); //是否还在post boolean isPosting; //post所在线程是否为主线程 boolean isMainThread; //subscription和Event是在取消的时候用到,包括canceled Subscription subscription; Object event; //是否取消post boolean canceled;}
isMainThread,在EventBus内部会根据当前线程决定是否切换线程,所以这个方法也先抛出来
/** * Checks if the current thread is running in the main thread. * 校验当前是否在主线程运行 * If there is no main thread support (e.g. non-Android), "true" is always returned. In that case MAIN thread * 如果没有主线程(例如非安卓设备),会一直返回true。 * 在这种情况下,主线程订阅者总是运行在posting线程(即调用线程) * 而后台订阅者总是运行在backgroundPoster(这是一个成员变量)。 * subscribers are always called in posting thread, and BACKGROUND subscribers are always called from a background * poster. */private boolean isMainThread() { return mainThreadSupport == null || mainThreadSupport.isMainThread();}
mainThreadSupport
private final MainThreadSupport mainThreadSupport;//构造方法里面mainThreadSupport = builder.getMainThreadSupport();//EventBusBuilder.getMainThreadSupportMainThreadSupport getMainThreadSupport() { if (mainThreadSupport != null) { return mainThreadSupport; } else if (AndroidLogger.isAndroidLogAvailable()) { Object looperOrNull = getAndroidMainLooperOrNull(); return looperOrNull == null ? null : new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull); } else { return null; }}
再继续深入就会没完没了,所以这里直接说清getMainThreadSupport的作用。Builder里面的mainThreadSupport是没有提供set方法的,所以只有在调用getMainThreadSupport方法之后才会初始化
mainThreadSupport。所以第一次调用绝对为空。
if (AndroidLogger.isAndroidLogAvailable()): 通过判断是否存在 android.util.Log 这个类来决定是否调用getAndroidMainLooperOrNull这个方法。这个方法实际上就是调用Looper.getMainLooper()获取主线程的Looper。
如果Looper不为空,就创建一个MainThreadSupport对象。
从这段源码可知,如果找不到 android.util.Log 这个类,就会返回空。个人认为这是一种判断当前项目是否为一个Android项目的方式。
post代码
/** Posts the given event to the event bus. */public void post(Object event) { //获取一个当前线程的PostingThreadState对象 PostingThreadState postingState = currentPostingThreadState.get(); //获取Event Queue List<Object> eventQueue = postingState.eventQueue; //将接收到的Event加入到EventQueue eventQueue.add(event); //如果现在在Posting,就结束方法//从上面这几行代码可以得到如下信息//1:在单线程的情况下,posting过程只会执行一次//2:如果在执行的过程中,谁调用了post方法,会将Event添加到Event Queue并结束方法//3:再从下面的while (!eventQueue.isEmpty()) 可以得出,只要当前任务没有执行完成//就会不断地从EventQueue取出Event并执行//4:在多线程的情况下,以上限制将不起到任何作用,因为ThreadLocal只保证一个线程//获取到的对象是同一个,并不保证多线程获取到的都是同一个 if (!postingState.isPosting) { //在post之前,先确定调用线程是否为主线程 postingState.isMainThread = isMainThread(); //打开posting开关 postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { //不断地从Event Queue取出消息,并post,当外部新增消息的时候,也可以获取到 while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState); } } finally { //恢复变量的状态 postingState.isPosting = false; postingState.isMainThread = false; } }}
postSingleEvent
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; //从构造方法的注释可知,当该变量为true的时候,就会一直找Event的父类,并post if (eventInheritance) { List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); int countTypes = eventTypes.size(); for (int h = 0; h < countTypes; h++) { Class<?> clazz = eventTypes.get(h); //当有一个为true时就为true subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); } } else { subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); } //当没找到订阅方法的时候 if (!subscriptionFound) { //根据配置决定是否打印log if (logNoSubscriberMessages) { logger.log(Level.FINE, "No subscribers registered for event " + eventClass); } //根据配置决定是否post一个NoSubscriberEvent,这里判断eventClass != NoSubscriberEvent.class //应该是为了防止递归调用 if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } }}
postSingleEventForEventType
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; 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;}
postToSubscription
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { //根据不同的ThreadMode执行不同的代码 switch (subscription.subscriberMethod.threadMode) { //POSTIN表示不管当前是什么线程,都执行方法 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); }}
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); }}
handleSubscriberException:当出现异常的时候,做相应的处理
private void handleSubscriberException(Subscription subscription, Object event, Throwable cause) { if (event instanceof SubscriberExceptionEvent) { if (logSubscriberExceptions) { // Don't send another SubscriberExceptionEvent to avoid infinite event recursion, just log logger.log(Level.SEVERE, "SubscriberExceptionEvent subscriber " + subscription.subscriber.getClass() + " threw an exception", cause); SubscriberExceptionEvent exEvent = (SubscriberExceptionEvent) event; logger.log(Level.SEVERE, "Initial event " + exEvent.causingEvent + " caused exception in " + exEvent.causingSubscriber, exEvent.throwable); } } else { if (throwSubscriberException) { throw new EventBusException("Invoking subscriber failed", cause); } if (logSubscriberExceptions) { logger.log(Level.SEVERE, "Could not dispatch event: " + event.getClass() + " to subscribing class " + subscription.subscriber.getClass(), cause); } if (sendSubscriberExceptionEvent) { SubscriberExceptionEvent exEvent = new SubscriberExceptionEvent(this, cause, event, subscription.subscriber); post(exEvent); } }}
至于线程怎么切换的,内容有点多,看下面
线程切换
线程切换主要涉及到以下4个字段
//切换到主线程的Posterprivate final Poster mainThreadPoster;//切换到子线程的Posterprivate final BackgroundPoster backgroundPoster;//无论当前是什么线程,都直接扔到这里执行private final AsyncPoster asyncPoster;//线程池,backgroundPoster和asyncPoster最终都是交给该线程池去执行任务的private final ExecutorService executorService;mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;backgroundPoster = new BackgroundPoster(this);asyncPoster = new AsyncPoster(this);executorService = builder.executorService;
Poster: 上面3个Poster都是该类的实现类,所以看一下规范的代码吧
/** * Posts events. * * @author William Ferguson */interface Poster { /** * Enqueue an event to be posted for a particular subscription. * 将要为特定订阅发布的事件排队。 * * @param subscription Subscription which will receive the event. * 将接收事件的订阅。 * @param event Event that will be posted to subscribers. * 将发布到订阅者的事件。 */ void enqueue(Subscription subscription, Object event);}
invokeSubscriber:几个Poster最终会通过EventBus的这个方法执行获取到的方法
/** * Invokes the subscriber if the subscriptions is still active. Skipping subscriptions prevents race conditions * between {@link #unregister(Object)} and event delivery. Otherwise the event might be delivered after the * subscriber unregistered. This is particularly important for main thread delivery and registrations bound to the * live cycle of an Activity or Fragment. * 如果订阅仍处于活跃状态,则调用订阅者。跳过订阅可防止{@link#unregister(Object)}和事件传递之间的竞争 * 条件。否则,事件可能在订阅者注销后传递。这对于主线程交付和绑定到Activity或Fragment的生命周期的注册特别 * 重要。 */void invokeSubscriber(PendingPost pendingPost) { //获取存储在PendingPost里面的Event Object event = pendingPost.event; //获取存储在PendingPost里面的Subscription Subscription subscription = pendingPost.subscription; //回收PendingPost并放入到PendingPost池里面,供下次使用 PendingPost.releasePendingPost(pendingPost); if (subscription.active) { //这个方法和post提到的invokeSubscriber方法是同一个 invokeSubscriber(subscription, event); }}
PendingPostQueue
想了一小时都想不出为什么PendingPostQueue的代码那样写就能做到入队和出队,在百度找了好久关于EventBus分析的文章也没看到有人提及,所以关于PendingPostQueue的内容不会过多的赘述。如果有人知道为什么能那样做,麻烦在评论区告诉我,非常感谢。
HandlerPoster:mainThreadPoster实际上创建出来的就是该类
public class HandlerPoster extends Handler implements Poster { //将要执行的任务加入并取出的队列 private final PendingPostQueue queue; //方法最大的执行事件,在EventBus传递进来的是10毫秒 //当一个方法执行的时间超过10毫秒,就会sendMessage。说实话,看不懂这样的作用 private final int maxMillisInsideHandleMessage; //最终通过该对象调用EventBus的invokeSubscriber方法 private final EventBus eventBus; //是否处于活跃,对于该对象来说,就是用来判断当前Handler是否在运行handleMessage private boolean handlerActive; protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { super(looper); this.eventBus = eventBus; this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; queue = new PendingPostQueue(); } public void enqueue(Subscription subscription, Object event) { //从PendingPost池里面取出一个PendingPost PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized (this) { //将消息加入到消息队列 queue.enqueue(pendingPost); //没有初始值,所以默认是false,当false的时候,就sendMesssage if (!handlerActive) { handlerActive = true; if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); } } } } @Override public void handleMessage(Message msg) { boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); //进来之后就while循环 while (true) { //不断地从PendingPost取出消息执行,从而减少sendMessage和handleMessage的调用次数 //当取不到消息的时候,就结束运行,并将handlerActive置为false //这样的话上面的enqueue方法就会再次sendMessage PendingPost pendingPost = queue.poll(); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = queue.poll(); if (pendingPost == null) { handlerActive = false; return; } } } eventBus.invokeSubscriber(pendingPost); long timeInMethod = SystemClock.uptimeMillis() - started; //当两次的时间大于或等于maxMillisInsideHandleMessage的时候,就sendMessage if (timeInMethod >= maxMillisInsideHandleMessage) { if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); } //由于这个时候sendMessage,所以必须为true rescheduled = true; return; } } } finally { handlerActive = rescheduled; } }}
BackgroundPoster
/** * Posts events in background. * * @author Markus */final class BackgroundPoster implements Runnable, Poster { private final PendingPostQueue queue; private final EventBus eventBus; //该变量的作用和上面的Handler的handlerActive作用是一样的 private volatile boolean executorRunning; 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); if (!executorRunning) { executorRunning = true; //获取EventBus的线程池,并在当前对象的run方法执行 eventBus.getExecutorService().execute(this); } } } @Override public void run() { try { try { while (true) { //最多等待1000毫秒获取消息,当PendingPost通过enqueue插入任务之后,很快就能获取到PendingPost对象 //为什么说最多,下面会贴出源码做出解释 PendingPost pendingPost = queue.poll(1000); //下面这个和Handler一样,没什么好讲的 if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = queue.poll(); if (pendingPost == null) { executorRunning = false; return; } } } eventBus.invokeSubscriber(pendingPost); } } catch (InterruptedException e) { eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e); } } finally { executorRunning = false; } }}
PendingPostQueue的部分代码
synchronized void enqueue(PendingPost pendingPost) { //前面我也说过,插入队列的方法的代码看不懂,所以这里不解释,看最后一行的notifyAll 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();}//再看这里,head即PendingPost对象。当head为空的时候,表示该队列里面没有PendingPost对象//这个时候就等待,等待时间由外部传递,上面传递的是1000毫秒//当有人调用enqueue的时候,就会notifyAll,所以这里就不再等待,而是调用poll取出任务synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException { if (head == null) { wait(maxMillisToWait); } return poll();}
AsyncPoster
/** * Posts events in background. * * @author Markus */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() { //可以看到 ASYNC 就不像 MAIN 和 BACKGROUND 一样,慢慢等待某个任务执行完成再执行下个任务 //而是只要拿到任务就直接执行 PendingPost pendingPost = queue.poll(); if(pendingPost == null) { throw new IllegalStateException("No pending post available"); } eventBus.invokeSubscriber(pendingPost); }}
线程切换的内容就这些,主要是针对几个Poster分析他们的源码,搞清楚他们的原理和运作方式,加深对EventBus的理解。后面在使用EventBus的时候,就可以使用更合适的线程模式。并且在分析的过程中也学习到一些知识,比如HandlerPoster这种设计方式,减少sendMessage和handleMessage的调用。
其他代码
上面主要是针对一些主要的方法进行分析,下面把一些有一定作用,但没有提到的代码贴出来分析。
EventBusBuilder
EventBus.lookupAllEventTypes
EventBus.cancelEventDelivery
EventBus.removeStickyEvent
EventBus.isRegistered
EventBus.clearCaches
EventBus.hasSubscriberForEvent
EventBusBuilder
EventBus.builder
public static EventBusBuilder builder() { return new EventBusBuilder();}
EventBusBuilder
/** * Creates EventBus instances with custom parameters and also allows to install a custom default EventBus instance. * Create a new builder using {@link EventBus#builder()}. */@SuppressWarnings("unused")public class EventBusBuilder { //EventBus所使用的线程池 private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(); //下面大部分在EvnetBus的构造方法讲过了,只提重要的或没提过的 boolean logSubscriberExceptions = true; boolean logNoSubscriberMessages = true; boolean sendSubscriberExceptionEvent = true; boolean sendNoSubscriberEvent = true; boolean throwSubscriberException; boolean eventInheritance = true; //在分析Finder的时候提到,当该变量为false时候,会尝试使用两种方式去找到订阅方法 boolean ignoreGeneratedIndex; boolean strictMethodVerification; //这里直接使用上面的线程池常量 ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; //找了一下EventBus对他的使用,只在下面的一个方法有用到,外部并没有使用,不清楚其作用 List<Class<?>> skipMethodVerificationForClasses; //下面有一个addIndex方法,就是将SubscriberInfoIndex添加到这里来,最后拿给Finder使用 List<SubscriberInfoIndex> subscriberInfoIndexes; Logger logger; MainThreadSupport mainThreadSupport; EventBusBuilder() { } /** Default: true */ public EventBusBuilder logSubscriberExceptions(boolean logSubscriberExceptions) { this.logSubscriberExceptions = logSubscriberExceptions; return this; } /** Default: true */ public EventBusBuilder logNoSubscriberMessages(boolean logNoSubscriberMessages) { this.logNoSubscriberMessages = logNoSubscriberMessages; return this; } /** Default: true */ public EventBusBuilder sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent) { this.sendSubscriberExceptionEvent = sendSubscriberExceptionEvent; return this; } /** Default: true */ public EventBusBuilder sendNoSubscriberEvent(boolean sendNoSubscriberEvent) { this.sendNoSubscriberEvent = sendNoSubscriberEvent; return this; } /** * Fails if an subscriber throws an exception (default: false). * * Tip: Use this with BuildConfig.DEBUG to let the app crash in DEBUG mode (only). This way, you won't miss * exceptions during development. * 默认为false。如果为true,当在执行订阅方法的时候抛出异常的时候,会抛出一个EventBusException。 * 建议使用BuildConfig.DEBUG来赋值,这样就不会在开发的时候错过异常。 */ public EventBusBuilder throwSubscriberException(boolean throwSubscriberException) { this.throwSubscriberException = throwSubscriberException; return this; } /** * By default, EventBus considers the event class hierarchy (subscribers to super classes will be notified). * Switching this feature off will improve posting of events. For simple event classes extending Object directly, * we measured a speed up of 20% for event posting. For more complex event hierarchies, the speed up should be * greater than 20%. * * However, keep in mind that event posting usually consumes just a small proportion of CPU time inside an app, * unless it is posting at high rates, e.g. hundreds/thousands of events per second. * * 文档太长,就不看了,默认为true。具体作用在解释EventBus源码的时候也提过了,在post的时候,会找到该 * Event所有的父类和父接口,并对他们post。说实话,就我个人而言,在开发中还没遇过这样的需求,所以如果 * 在开发的时候没有这种需求,还是手动调用EventBus.build(),然后置为false吧,提升效率。 */ public EventBusBuilder eventInheritance(boolean eventInheritance) { this.eventInheritance = eventInheritance; return this; } /** * Provide a custom thread pool to EventBus used for async and background event delivery. This is an advanced * setting to that can break things: ensure the given ExecutorService won't get stuck to avoid undefined behavior. * 也可以自己指定EventBus的线程池 */ public EventBusBuilder executorService(ExecutorService executorService) { this.executorService = executorService; return this; } /** * Method name verification is done for methods starting with onEvent to avoid typos; using this method you can * exclude subscriber classes from this check. Also disables checks for method modifiers (public, not static nor * abstract). * * 对以onEvent开头的方法进行方法名验证,以避免拼写错误;使用此方法,您可以从此检查中排除订阅者。还禁止 * 检查方法修饰符(public、not static、not abstract)。 * * 这个就是上面提到的不知道有什么作用的的字段,我在接触EventBus的时候就可以自定义方法名称了,所以对需 * 要onEvent开头这件事不清楚。 * 我猜测是不是EventBus不想删掉这段代码,所以才会出现看到这个字段,又没有找到使用的地方。 */ public EventBusBuilder skipMethodVerificationFor(Class<?> clazz) { if (skipMethodVerificationForClasses == null) { skipMethodVerificationForClasses = new ArrayList<>(); } skipMethodVerificationForClasses.add(clazz); return this; } /** Forces the use of reflection even if there's a generated index (default: false). */ public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) { this.ignoreGeneratedIndex = ignoreGeneratedIndex; return this; } /** Enables strict method verification (default: false). */ public EventBusBuilder strictMethodVerification(boolean strictMethodVerification) { this.strictMethodVerification = strictMethodVerification; return this; } /** Adds an index generated by EventBus' annotation preprocessor. */ public EventBusBuilder addIndex(SubscriberInfoIndex index) { if (subscriberInfoIndexes == null) { subscriberInfoIndexes = new ArrayList<>(); } subscriberInfoIndexes.add(index); return this; } /** * Set a specific log handler for all EventBus logging. * * By default all logging is via {@link android.util.Log} but if you want to use EventBus * outside the Android environment then you will need to provide another log target. */ public EventBusBuilder logger(Logger logger) { this.logger = logger; return this; } Logger getLogger() { if (logger != null) { return logger; } else { return Logger.Default.get(); } } MainThreadSupport getMainThreadSupport() { if (mainThreadSupport != null) { return mainThreadSupport; } else if (AndroidLogger.isAndroidLogAvailable()) { Object looperOrNull = getAndroidMainLooperOrNull(); return looperOrNull == null ? null : new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull); } else { return null; } } static Object getAndroidMainLooperOrNull() { try { return Looper.getMainLooper(); } catch (RuntimeException e) { // Not really a functional Android (e.g. "Stub!" maven dependencies) return null; } } /** * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be * done only once before the first usage of the default EventBus. * * @throws EventBusException if there's already a default EventBus instance in place * * 在构建完EventBus之后,可以使用该方法将构建完成的EvnetBus对象存储到EvnetBus的defaultInstance里面 * 下次要使用EventBus的时候就直接调用EventBus.getDefault()就可以了。 * 不过需要注意的是,如果EventBus.defaultInstance不等于空就会抛出异常。所以这个方法要谨慎调用。 * * 有了这个方法,就没有必要使用Application将自己构建的EventBus存起来,而是在构建完成之后调用这个方法 * 存到EventBus的defaultInstance里面,下次使用的时候就直接EventBus.getDefault()。 */ public EventBus installDefaultEventBus() { synchronized (EventBus.class) { if (EventBus.defaultInstance != null) { throw new EventBusException("Default instance already exists." + " It may be only set once before it's used the first time to ensure consistent behavior."); } EventBus.defaultInstance = build(); return EventBus.defaultInstance; } } /** Builds an EventBus based on the current configuration. */ public EventBus build() { return new EventBus(this); }}
EventBus.lookupAllEventTypes
上面提到eventInheritance这个字段的时候,才想起来EventBus这个私有方法,该方法就是获取一个Event的所有接口和父类/** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) { synchronized (eventTypesCache) { //EventType列表 List<Class<?>> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { eventTypes = new ArrayList<>(); Class<?> clazz = eventClass; //只要当前类不为空,就继续找 while (clazz != null) { eventTypes.add(clazz); //找到当前类所有的接口,并添加进去 addInterfaces(eventTypes, clazz.getInterfaces()); //将父类的Class对象赋到当前类 clazz = clazz.getSuperclass(); } eventTypesCache.put(eventClass, eventTypes); } return eventTypes; }}/** Recurses through super interfaces. */static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) { for (Class<?> interfaceClass : interfaces) { if (!eventTypes.contains(interfaceClass)) { eventTypes.add(interfaceClass); //递归获取接口的父接口 addInterfaces(eventTypes, interfaceClass.getInterfaces()); } }}
EventBus.cancelEventDelivery
取消事件,这也算是一个能起到很大作用的方法/** * Called from a subscriber's event handling method, further event delivery will be canceled. Subsequent * subscribers * won't receive the event. Events are usually canceled by higher priority subscribers (see * {@link Subscribe#priority()}). Canceling is restricted to event handling methods running in posting thread * {@link ThreadMode#POSTING}. * 从订阅者的事件处理方法调用后,进一步的事件传递将被取消。后续订阅者将不会收到该事件。事件通常被高优先级订 * 阅者取消(see{@link Subscribe#priority()})。取消仅限于在发布线程{@link ThreadMode# post}中运行的事 * 件处理方法。 */public void cancelEventDelivery(Object event) { //获取当前线程的PostingThreadState对象 PostingThreadState postingState = currentPostingThreadState.get(); //如果现在不是在Posting if (!postingState.isPosting) { throw new EventBusException( "This method may only be called from inside event handling methods on the posting thread");//如果event == null } else if (event == null) { throw new EventBusException("Event may not be null");//如果正在posting的Event和传递过来的Event不是同一个 } else if (postingState.event != event) { throw new EventBusException("Only the currently handled event may be aborted");//如果现在在Posting的方法的ThreadMode不是POSTING } else if (postingState.subscription.subscriberMethod.threadMode != ThreadMode.POSTING) { throw new EventBusException(" event handlers may only abort the incoming event"); } //上面所有条件都为false的时候,才能cancel //所以可以看出,cancel的条件是比较严格的,所以最好谨慎使用 postingState.canceled = true;}
EventBus.removeStickyEvent
移除粘性事件/** * Remove and gets the recent sticky event for the given event type. * * 使用Class的方法将事件从stickyEvents移除 * @see #postSticky(Object) */public <T> T removeStickyEvent(Class<T> eventType) { synchronized (stickyEvents) { return eventType.cast(stickyEvents.remove(eventType)); }}/** * Removes the sticky event if it equals to the given event. * * @return true if the events matched and the sticky event was removed. */public boolean removeStickyEvent(Object event) { synchronized (stickyEvents) { Class<?> eventType = event.getClass(); Object existingEvent = stickyEvents.get(eventType); //如果存在该事件,并且两个事件是同一个,才能移除 if (event.equals(existingEvent)) { stickyEvents.remove(eventType); return true; } else { return false; } }}/** * Removes all sticky events. * * 移除所有 */public void removeAllStickyEvents() { synchronized (stickyEvents) { stickyEvents.clear(); }}
getStickyEvent
/** * Gets the most recent sticky event for the given type. * * 从上面的removeStickyEvent(Object event)可以看到,需要存在并且是同一个 * 如果在post的时候没有存起来呢,那就可以使用该方法获取,再移除 * @see #postSticky(Object) */public <T> T getStickyEvent(Class<T> eventType) { synchronized (stickyEvents) { return eventType.cast(stickyEvents.get(eventType)); }}
EventBus.isRegistered
判断对象是否已经注册过了public synchronized boolean isRegistered(Object subscriber) { return typesBySubscriber.containsKey(subscriber);}
EventBus.clearCaches
清理缓存/** For unit test primarily. */public static void clearCaches() { SubscriberMethodFinder.clearCaches(); eventTypesCache.clear();}//SubscriberMethodFinder.clearCaches();static void clearCaches() { METHOD_CACHE.clear();}
EventBus.hasSubscriberForEvent
某个Event是否存在订阅者public boolean hasSubscriberForEvent(Class<?> eventClass) { //找到所有父类和接口 List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); if (eventTypes != null) { int countTypes = eventTypes.size(); for (int h = 0; h < countTypes; h++) { Class<?> clazz = eventTypes.get(h); CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { //从subscriptionsByEventType取出Subscription列表 subscriptions = subscriptionsByEventType.get(clazz); } //当不为空的时候返回true if (subscriptions != null && !subscriptions.isEmpty()) { return true; } } } return false;}
个人推荐用法
从上面的源码分析可知,使用使用addIndex优化、如果可以确定Event不需要找到所有父类和父接口,就让eventInheritance为false、可以使用BuildConfig.DEBUG为throwSubscriberException赋上必要的值,在开发的时候执行一个方法如果出现问题就会抛出异常所以我提供了下面这段示例代码,可以用于参考。
EBApplication
class EBApplication : Application() { override fun onCreate() { super.onCreate() initEventBus() } private fun initEventBus() { EventBus.builder() //当一个类里面的方法比较多的时候,才有必要这样做。如果不多,就看对性能有没有什么要求吧 //因为这种写法其实也挺麻烦的,直接用注解相对来说比较简单 .addIndex(EventBusSIIndex()) //经测试,把这行代码注释掉,即使方法在执行的过程中出现异常,APP也能正常运行 //而如果没有注释,出现异常的时候,就直接抛出异常,APP停止运行 .throwSubscriberException(BuildConfig.DEBUG) //个人认为这种方式是没必要的,所以直接关了,这个具体看使用场景吧 .eventInheritance(false) //将构建完成EvnetBus安装到EventBus的defaultInstance里面,下次使用的时候就可以直接getDefault .installDefaultEventBus() }}
EventBusSIIndex
class EventBusSIIndex : SubscriberInfoIndex { override fun getSubscriberInfo(subscriberClass: Class<*>?): SubscriberInfo? { return when (subscriberClass) { EBTest1Activity::class.java -> EBTest1SubInfo() else -> null } }}
EBTest1SubInfo
class EBTest1SubInfo : SubscriberInfo { override fun getSubscriberClass(): Class<*>? = null override fun getSubscriberMethods(): Array<SubscriberMethod> { val eventType = EBMessage::class.java val subscriberType = EBTest1Activity::class.java val indexTest1 = subscriberType.getMethod("indexTest1", eventType) val indexTest2 = subscriberType.getMethod("indexTest2", eventType) return arrayOf(SubscriberMethod(indexTest1, eventType, ThreadMode.MAIN, 0, false) , SubscriberMethod(indexTest2, eventType, ThreadMode.MAIN, 0, false)) } override fun getSuperSubscriberInfo(): SubscriberInfo? = null override fun shouldCheckSuperclass() = false}
EBTest1Activity
class EBTest1Activity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_ebtest1) EventBus.getDefault().register(this) start_btn.setOnClickListener { startActivity(Intent(this, EBTest2Activity::class.java)) } EventBus.getDefault().post(EBMessage()) } fun indexTest1(ignore: EBMessage) { Log.d("EBTest1Activity", "indexTest1") } fun indexTest2(ignore: EBMessage) { Log.d("EBTest1Activity", "indexTest2") } override fun onDestroy() { super.onDestroy() EventBus.getDefault().unregister(this) }}
EBTest2Activity
class EBTest2Activity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) EventBus.getDefault().register(this) EventBus.getDefault().post(EBMessage()) } @Subscribe fun annotationTest1(ignore: EBMessage) { Log.d("EBTest2Activity", "annotationTest1") } @Subscribe fun annotationTest2(ignore: EBMessage) { Log.d("EBTest2Activity", "annotationTest2") } @Subscribe fun exceptionTest(ignore: EBMessage){ throw RuntimeException("test EventBus throw Exception") } override fun onDestroy() { super.onDestroy() EventBus.getDefault().unregister(this) }}
在测试的时候,可以发现,即使addIndex,使用注解的方法也可以被找到,所以证明这两种方式是可以共同存在的。
还有个问题,混淆。如果订阅方法使用Subscribe注解,那只要将EventBus在github写的混淆规则复制过来就行。那SubscriberInfo的方式要怎么办?其实很简单,直接在订阅方法上贴上Subscribe即可。反正只要findState.subscriberInfo不为空,就不会使用反射的方式寻找订阅方法。
还有另一种方式:自定义注解
EventBus的Subscribe
@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.METHOD})public @interface Subscribe { ...}
我自己写的注解
@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.METHOD})public @interface ProGuardIgnore { }
简单来说,就是抄Subscribe的代码。再看看EventBus在github上写的忽略代码
-keepattributes *Annotation*-keepclassmembers class * { @org.greenrobot.eventbus.Subscribe ;}-keep enum org.greenrobot.eventbus.ThreadMode { *; } # And if you use AsyncExecutor:-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { (java.lang.Throwable);}
所以只要复制第2到第4行的代码,把全限定名改成自己的就行了
-keepclassmembers class * { @your.package.name.ProGuardIgnore ;}
后记
EventBus的源码相对来说还是比较简单的,大部分方法都没有很长的调用链,都能一下子就找到最终调用的方法。所以如果有时间的话,还是比较推荐去看一看。不过也不能只是看,EventBus内部还是有很多东西可以学习的,比如对象池、源码里面的各个synchronized代码块等。更多相关文章
- 菜单栏上没有android机器人的图标(AVD)的解决方法
- Android(安卓)root的两种方法 -- udev漏洞和setuid漏洞
- android 铃声设置流程
- android 中如何获取camera当前状态
- 【androd基础】之Android(安卓)返回键的调用
- Android(安卓)ApiDemo学习(二)notification——2 Notifying Servic
- Android(安卓)AIDl来实现进程间通讯
- android获取时间差的方法
- App优化之提升你的App启动速度之实例挑战