使用greenrobot EventBus,如果基类和派生类都订阅了,会发生什么?

时间:2019-03-31 17:37:45

标签: java greenrobot-eventbus

我正在使用greenrobot EventBus。

如果我有一个基类B和一个派生类D,并且都在函数f中订阅了事件E:

class E {}

class B {
    @Subscribe
    public f(E e) {}
}

class D extends B {
    @Subscribe
    public f(E e) {}
}

发送事件并且存在类型D的对象时会发生什么?

  1. B.f()D.f()都在对象上被调用
  2. 仅调用D.f()
  3. D.f()被调用两次(每次注册一次)

1 个答案:

答案 0 :(得分:0)

对3.1.1版有效

假设您刚刚注册了D的实例:

public class Scratch4 {
    public static void main(String args[]) {
        EventBus.getDefault()
                .register(new D());

        EventBus.getDefault()
                .post(new E());

    }
}

并且:

public class B {
    @Subscribe
    public void f(E e) {
        System.out.println("IN B");
    }
}

public class D extends B {
    @Subscribe
    public void f(E e) {
        System.out.println("IN D");
    }
}

然后main()方法产生:

IN D

这是因为D覆盖了B中的方法void f(E e)

下面解释了为什么只一次调用该方法

具体来说,当您注册订户时,将使用register方法:

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

仅注册一种方法(D::f)。

在后台,FindState对象用于捕获查找。

随后,findState.checkAdd(method, eventType)首先在SubscriberMethodFinder::findUsingReflectionInSingleClass的{​​{1}}中运行(我们正在注册一个D,它在层次结构的底部),因此它返回true-这会导致添加D::f方法来进行订阅通知。

然后它沿层次结构前进。

因此,第二次调用(使用D::f)。这将返回false-使其不被添加到B::f中。

此拒绝是因为findState禁止在当前SubscribeMethodFinder::checkAddWithMethodSignature中被子方法取代的方法成为候选方法:

FindState

下面解释了为什么仅调用子类的无效实现

这是由于我们无法选择要在层次结构方法中选择哪种类型的事实而进一步实施的-如果我们调用被覆盖的方法,则将调用子级的版本。静态和运行时类型无关紧要。

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)) {
        // Only add if not already found in a sub class
        return true;
    } else {
        // Revert the put, old class is further down the class hierarchy
        subscriberClassByMethodKey.put(methodKey, methodClassOld);
        return false;
    }
}

收益:

public class Scratch4 {
    public static void main(String args[]) throws Exception {
        B b = new D();

        Class<B> bClazz = B.class;
        Method bClazzMethod = bClazz.getMethod("f", E.class);

        bClazzMethod.invoke(b, new E());
    }
}

如果要制作IN D

B

然后public class B { @Subscribe public void somethingThatIsNotF(E e) { System.out.println("IN B"); } } 方法将产生:

main()

我猜该顺序是由子对父顺序确定的(即IN D IN B ,因此D extends B排在第一位)。