解決EventBus在子類重寫父類2個(gè)訂閱函數(shù)時(shí)Crash

摘要

解決: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é)果:

  1. anyMethodByEventType直接插入本次method
  2. eventType相同,拿到第一次的method
  3. checkAddWithMethodSignature的時(shí)候,因?yàn)榉椒灰粯?,本次訂閱被?dāng)做有效值,記錄到subscriberClassByMethodKey
  4. 最后把包裹methodFindState插入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é)果:

  1. anyMethodByEventType直接插入本次method
  2. eventType相同,拿到第二次的FindState
  3. 做檢查時(shí),FindState不是method 注意:這一步?jīng)]有把本次的method包裹成FindState
  4. 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é)果:

  1. anyMethodByEventType直接插入本次method
  2. eventType相同,拿到第二次的method 注意:這就是引起Crash的位置
  3. 做檢查時(shí),FindStatemethod
  4. 最終引起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);
    }
}

參考資料

  1. kakaxicm的github
  2. EventBus的issue
  3. kakaxicm關(guān)于EventBus的介紹一
  4. kakaxicm關(guān)于EventBus的介紹二
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容