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

问题描述 投票:0回答:1

我正在使用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()被召唤两次(每次登记一次)
java greenrobot-eventbus
1个回答
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中运行D::f(我们正在注册一个D,它位于层次结构的底部),所以它返回true - 这导致D::f方法被添加用于订阅通知。

然后它走向层次结构。

所以,它第二次被调用(使用B::f)。返回false - 导致它不被添加到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所以D首先出现)。

© www.soinside.com 2019 - 2024. All rights reserved.