将所有regestired侦听器获取为可观察值

时间:2016-05-11 12:07:29

标签: javafx

如何让所有侦听器获得可观察的值?我可以扩展该类并覆盖addListenerremoveListener方法以将它们存储在一个集合中。但是该集合应该已经以某种方式存储在可观察值内。我怎么能得到那套呢?

2 个答案:

答案 0 :(得分:0)

我找到了解决方法,你无法直接访问Listeners列表,但是如果你使用调试器(我使用IntelliJ)你可以看到它,如果你在ObservableProprty里面看这样:(我希望这是足够清楚) enter image description here

另一种方式:(你是个聪明人,你会知道如何适应你的情况)

    //SimpleFloatProperty we want to find its Listeners
    FloatPropertyBase f=ampPS.currentProperty();
    Object value;
    ChangeListener[] list;
    ChangeListener changeListener=null;
    Field field = null;
    try {
        field = FloatPropertyBase.class.getDeclaredField("helper");
        field.setAccessible(true);
        value = field.get(f);
        try {
            field = value.getClass().getDeclaredField("listener");
            field.setAccessible(true);
            changeListener =(WeakChangeListener)field.get(value);
        }catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        try {
            field = value.getClass().getDeclaredField("changeListeners");
            field.setAccessible(true);
            list =(ChangeListener[])field.get(value);
        }catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

结果: enter image description here

(注意1个监听器或1个以上的监听器之间的区别)

我正在为几种类型的值添加示例

public static ChangeListener[] getChangeListeners(ObservableValue observableValue){

    Object value;
    ChangeListener[] list=null;
    ChangeListener changeListener=null;
    Field field = null;

    try {
        if(observableValue instanceof SimpleFloatProperty ){
            field = FloatPropertyBase.class.getDeclaredField("helper");
        }
        else if(observableValue instanceof SimpleBooleanProperty ){
            field = BooleanPropertyBase.class.getDeclaredField("helper");
        }
        else if(observableValue instanceof SimpleIntegerProperty ){
            field = IntegerPropertyBase.class.getDeclaredField("helper");
        }
        field.setAccessible(true);
        value = field.get(observableValue);
        try {
            field = value.getClass().getDeclaredField("listener");
            field.setAccessible(true);
            changeListener =(ChangeListener)field.get(value);
        }catch (NoSuchFieldException e) {
            //e.printStackTrace();
        }
        try {
            field = value.getClass().getDeclaredField("changeListeners");
            field.setAccessible(true);
            list =(ChangeListener[])field.get(value);
        }catch (NoSuchFieldException e) {
            //e.printStackTrace();
        }
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    if(list!=null){
        return list;
    }
    else {
        ChangeListener[] changeListeners = new  ChangeListener[1];
        changeListeners[0]=changeListener;
        return changeListeners;
    }
}

我称之为:

    SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(true);
    SimpleFloatProperty simpleFloatProperty = new SimpleFloatProperty(0);
    SimpleIntegerProperty simpleIntegerProperty = new SimpleIntegerProperty(1);
    booleanProperty.addListener(changeListener);
    simpleFloatProperty.addListener(changeListener);
    simpleIntegerProperty.addListener(changeListener);
    simpleIntegerProperty.addListener(changeListener);
    System.out.println(getChangeListeners(booleanProperty).length);
    System.out.println(getChangeListeners(simpleFloatProperty).length);
    System.out.println(getChangeListeners(simpleIntegerProperty).length);

结果:enter image description here

所以我收到警告,但工作完成了!

答案 1 :(得分:0)

ObservableValue.removeListener的文档说明:

如果给定的侦听器先前尚未注册(即从未添加过),则此方法调用为空操作。

如果要避免反射,这会留下一些选择。

首先,在添加侦听器之前调用removeListener,例如:

final var property = someProperty();
final var listener = getListener();
property.removeListener( listener );
property.addListener( listener );

此技术等效于使用Set,只要getListener()始终返回相同的对象引用。 (如果同一类的不同对象引用覆盖equals以返回true,但您必须仔细检查,此可能也有效。)

缺点是必须保留对添加的侦听器的引用,这可能需要一个新的类,但至少需要一个新的实例变量。

第二,保留已注册侦听器的地图,以达到以下效果:

final HashMap<ObservableValue<?>, Object> map = new HashMap<>();
final var property = someProperty();
final var listener = getListener();
map.computeIfAbsent( property, p -> {
  property.addListener( listener );
  return property;
});

尽管问题正在寻找侦听器列表,但我怀疑问题的意图是避免添加重复的侦听器,这是常见的情况。