美文网首页
解决EventBus在子类重写父类2个订阅函数时Crash

解决EventBus在子类重写父类2个订阅函数时Crash

作者: 0一缕星光0 | 来源:发表于2019-11-07 17:53 被阅读0次

    摘要

    解决: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
    

    结果:

    1. anyMethodByEventType直接插入本次method
    2. eventType相同,拿到第一次的method
    3. checkAddWithMethodSignature的时候,因为方法名不一样,本次订阅被当做有效值,记录到subscriberClassByMethodKey
    4. 最后把包裹methodFindState插入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
    

    结果:

    1. anyMethodByEventType直接插入本次method
    2. eventType相同,拿到第二次的FindState
    3. 做检查时,FindState不是method 注意:这一步没有把本次的method包裹成FindState
    4. checkAddWithMethodSignature中,先把本次订阅插入,在将原先的订阅插入,作为替换

    第四次:EventBusBaseFragment#subscribeMessage1

    关键变量:

    methodClass:com.abelhu.androidstudy.ui.send.EventBusBaseFragment
    methodClassOld:com.abelhu.androidstudy.ui.send.SendFragment
    methodKey:subscribeMessage0>com.abelhu.androidstudy.message.SendMessage
    

    结果:

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

    参考资料

    1. kakaxicm的github
    2. EventBus的issue
    3. kakaxicm关于EventBus的介绍一
    4. kakaxicm关于EventBus的介绍二

    相关文章

      网友评论

          本文标题:解决EventBus在子类重写父类2个订阅函数时Crash

          本文链接:https://www.haomeiwen.com/subject/bqgvbctx.html