摘要
解決:EventBus在子類重寫父類2個(gè)訂閱函數(shù)時(shí)Crash。參考issure。
由于在重復(fù)注冊(cè)訂閱方法時(shí),在第三次注冊(cè)時(shí)沒(méi)有把method包裹成FindState,導(dǎo)致第四次注冊(cè)訂閱方法時(shí)走到了錯(cuò)誤的邏輯里面,引起本次的崩潰!
準(zhǔn)備
父類:
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的關(guān)鍵代碼:
// /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;
}
}
}
調(diào)查
第一次:注冊(cè)SendFragment#subscribeMessage0
關(guān)鍵變量:
methodClass:com.abelhu.androidstudy.ui.send.SendFragment
methodClassOld:null
methodKey:subscribeMessage0>com.abelhu.androidstudy.message.SendMessage
結(jié)果:method直接插入anyMethodByEventType,此時(shí)anyMethodByEventType里存放的是method
第二次:注冊(cè)SendFragment#subscribeMessage1
關(guān)鍵變量:
methodClass:com.abelhu.androidstudy.ui.send.SendFragment
methodClassOld:null
methodKey:subscribeMessage1>com.abelhu.androidstudy.message.SendMessage
結(jié)果:
-
anyMethodByEventType直接插入本次method -
eventType相同,拿到第一次的method - 在
checkAddWithMethodSignature的時(shí)候,因?yàn)榉椒灰粯?,本次訂閱被?dāng)做有效值,記錄到subscriberClassByMethodKey中 - 最后把包裹
method的FindState插入anyMethodByEventType,此時(shí)anyMethodByEventType里存放的是FindState
第三次:EventBusBaseFragment#subscribeMessage0
關(guān)鍵變量:
methodClass:com.abelhu.androidstudy.ui.send.EventBusBaseFragment
methodClassOld:com.abelhu.androidstudy.ui.send.SendFragment
methodKey:subscribeMessage0>com.abelhu.androidstudy.message.SendMessage
結(jié)果:
-
anyMethodByEventType直接插入本次method -
eventType相同,拿到第二次的FindState - 做檢查時(shí),
FindState不是method注意:這一步?jīng)]有把本次的method包裹成FindState - 在
checkAddWithMethodSignature中,先把本次訂閱插入,在將原先的訂閱插入,作為替換
第四次:EventBusBaseFragment#subscribeMessage1
關(guān)鍵變量:
methodClass:com.abelhu.androidstudy.ui.send.EventBusBaseFragment
methodClassOld:com.abelhu.androidstudy.ui.send.SendFragment
methodKey:subscribeMessage0>com.abelhu.androidstudy.message.SendMessage
結(jié)果:
-
anyMethodByEventType直接插入本次method -
eventType相同,拿到第二次的method注意:這就是引起Crash的位置 - 做檢查時(shí),
FindState是method - 最終引起
IllegalStateException
結(jié)論
由于在重復(fù)注冊(cè)訂閱方法時(shí),在第三次注冊(cè)時(shí)沒(méi)有把method包裹成FindState,導(dǎo)致第四次注冊(cè)訂閱方法時(shí)走到了錯(cuò)誤的邏輯里面,引起本次的崩潰!
解決
解決方法很簡(jiǎn)單了,只需要把anyMethodByEventType.put(eventType, this);挪動(dòng)一下位置,放到return的上方,讓所有的重復(fù)注冊(cè)都把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); // 注意:這一行被移動(dòng)了一下位置
return checkAddWithMethodSignature(method, eventType);
}
}