摘要
解决:EventBus在子类重写父类2个订阅函数时Crash。参考issure。
由于在重复注册订阅方法时,在第三次注册时没有把method
包裹成FindState
,导致第四次注册订阅方法时走到了错误的逻辑里面,引起本次的崩溃!
准备
父类:
open class EventBusBaseFragment : Fragment() {
@Subscribe
open fun subscribeMessage0(message: SendMessage) {
Log.d("EventBusBaseFragment", "EventBusBaseFragment subscribeMessage0")
}
@Subscribe
open fun subscribeMessage1(message: SendMessage) {
Log.d("EventBusBaseFragment", "EventBusBaseFragment subscribeMessage1")
}
}
子类:
open class SendFragment : EventBusBaseFragment() {
@Subscribe
override fun subscribeMessage0(message: SendMessage) {
Log.d("SendFragment", "SendFragment subscribeMessage0")
}
@Subscribe
override fun subscribeMessage1(message: SendMessage) {
Log.d("SendFragment", "SendFragment subscribeMessage1")
}
}
EventBus的关键代码:
// /org/greenrobot/eventbus/SubscriberMethodFinder.java
boolean checkAdd(Method method, Class> eventType) {
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
throw new IllegalStateException();
}
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
// /org/greenrobot/eventbus/SubscriberMethodFinder.java
private boolean checkAddWithMethodSignature(Method method, Class> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class> methodClass = method.getDeclaringClass();
Class> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
return true;
} else {
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
}
调查
第一次:注册SendFragment#subscribeMessage0
关键变量:
methodClass:com.abelhu.androidstudy.ui.send.SendFragment
methodClassOld:null
methodKey:subscribeMessage0>com.abelhu.androidstudy.message.SendMessage
结果:method
直接插入anyMethodByEventType
,此时anyMethodByEventType
里存放的是method
第二次:注册SendFragment#subscribeMessage1
关键变量:
methodClass:com.abelhu.androidstudy.ui.send.SendFragment
methodClassOld:null
methodKey:subscribeMessage1>com.abelhu.androidstudy.message.SendMessage
结果:
-
anyMethodByEventType
直接插入本次method
-
eventType
相同,拿到第一次的method
- 在
checkAddWithMethodSignature
的时候,因为方法名不一样,本次订阅被当做有效值,记录到subscriberClassByMethodKey
中 - 最后把包裹
method
的FindState
插入anyMethodByEventType
,此时anyMethodByEventType
里存放的是FindState
第三次:EventBusBaseFragment#subscribeMessage0
关键变量:
methodClass:com.abelhu.androidstudy.ui.send.EventBusBaseFragment
methodClassOld:com.abelhu.androidstudy.ui.send.SendFragment
methodKey:subscribeMessage0>com.abelhu.androidstudy.message.SendMessage
结果:
-
anyMethodByEventType
直接插入本次method
-
eventType
相同,拿到第二次的FindState
- 做检查时,
FindState
不是method
注意:这一步没有把本次的method
包裹成FindState
- 在
checkAddWithMethodSignature
中,先把本次订阅插入,在将原先的订阅插入,作为替换
第四次:EventBusBaseFragment#subscribeMessage1
关键变量:
methodClass:com.abelhu.androidstudy.ui.send.EventBusBaseFragment
methodClassOld:com.abelhu.androidstudy.ui.send.SendFragment
methodKey:subscribeMessage0>com.abelhu.androidstudy.message.SendMessage
结果:
-
anyMethodByEventType
直接插入本次method
-
eventType
相同,拿到第二次的method
注意:这就是引起Crash的位置 - 做检查时,
FindState
是method
- 最终引起
IllegalStateException
结论
由于在重复注册订阅方法时,在第三次注册时没有把method
包裹成FindState
,导致第四次注册订阅方法时走到了错误的逻辑里面,引起本次的崩溃!
解决
解决方法很简单了,只需要把anyMethodByEventType.put(eventType, this);
挪动一下位置,放到return
的上方,让所有的重复注册都把method
包裹成FindState
,就可以了,代码如下:
// /org/greenrobot/eventbus/SubscriberMethodFinder.java
boolean checkAdd(Method method, Class> eventType) {
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this); // 注意:这一行被移动了一下位置
return checkAddWithMethodSignature(method, eventType);
}
}
参考资料
- kakaxicm的github
- EventBus的issue
- kakaxicm关于EventBus的介绍一
- kakaxicm关于EventBus的介绍二