EventBus github:https://github.com/greenrobot/EventBus
我自己fork了EventBus的github,并在master分支的EventBus的module写了注释,可以看一看:https://github.com/nanjolnoSat/EventBus
本博客是基于EventBus3.2.0版本编写的,不同版本的代码可能有所不同。
如何使用
方法分析
其他代码
个人推荐用法
后记
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
线程切换
//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的成员变量分析得差不多了。
接下来对代码进行分析
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,就会调用这个方法。
/**
* 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的构造方法
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();
}
初始化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)
}
}
/** 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--;
}
}
}
}
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.getMainThreadSupport
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;
}
}
再继续深入就会没完没了,所以这里直接说清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个字段
//切换到主线程的Poster
private final Poster mainThreadPoster;
//切换到子线程的Poster
private 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
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);
}
}
/** 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());
}
}
}
/**
* 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;
}
/**
* 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));
}
}
public synchronized boolean isRegistered(Object subscriber) {
return typesBySubscriber.containsKey(subscriber);
}
/** For unit test primarily. */
public static void clearCaches() {
SubscriberMethodFinder.clearCaches();
eventTypesCache.clear();
}
//SubscriberMethodFinder.clearCaches();
static void clearCaches() {
METHOD_CACHE.clear();
}
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;
}
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 ;
}