美文网首页
解决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

    摘要 解决:EventBus在子类重写父类2个订阅函数时Crash。参考issure。 由于在重复注册订阅方法时,...

  • 2020-07-07-《C++虚函数》

    虚函数可以让子类重写函数 子类重写父类中的虚函数 重写与重载的区别?

  • 重写(=覆盖)、重载

    override(重写、覆盖): 子类在继承父类时,重写(重新实现)父类中的方法。 重写(覆盖)的规则: 重写方法...

  • c++函数的override overwrite overloa

    override (overwrite) 重写(=覆盖): 父子类间,子类覆盖父类的方法,函数名参数均相同,父类函...

  • python 在子类中增加__init__,并继承父类的__in

    问题 经常子类继承父类的时候,重写了init时,实例化子类,就不会调用父类已经定义的init 解决办法 要在子类中...

  • swift中子类重写父类的方法

    子类在主体中重写父类的方法 如果重写的父类方法在主体中,直接重写即可,如果重写的父类方法在extension中,父...

  • 8,Python面向对象3

    重写父类方法 1. 重写父类方法 所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同...

  • C++中多态

    多态成立的三个条件 有继承 有函数重写 有父类指针(父类引用)指向子类对象 多态原理 当类中声明虚函数时,编译器会...

  • python-面向对象——继承

    继承 可以多层继承,子类可以直接调用父类的父类的函数 重写 调用被重写的方法: 多继承 python支持多继承 所...

  • Swift 个人笔记

    在Swift中,子类可以对父类的函数进行重写。但是在重写的时候,要在函数名前加override。 而在oc中进行方...

网友评论

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

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