JavaFX InvalizationListener或ChangeListener

JavaFX InvalizationListener或ChangeListener,java,javafx,Java,Javafx,我只感兴趣的是一个财产是否发生了变化,而不是新的价值 注册invalizationListener而不是changeStener是否有利 我假设对属性的更改首先会使该属性无效,并通知所有无效侦听器。仅当注册了更改侦听器,或有人请求此属性时,才会“验证”该属性/重新计算该属性,并使用新值更新所有更改侦听器 因为我对实际值不感兴趣,所以我假设只侦听失效事件(属性已更改但未重新计算,某种中间状态)是一种性能优势。为此,您需要实现一个ChangeListener。只有当值变为无效时,才会执行invali

我只感兴趣的是一个财产是否发生了变化,而不是新的价值

注册
invalizationListener
而不是
changeStener
是否有利

我假设对属性的更改首先会使该属性无效,并通知所有无效侦听器。仅当注册了更改侦听器,或有人请求此属性时,才会“验证”该属性/重新计算该属性,并使用新值更新所有更改侦听器


因为我对实际值不感兴趣,所以我假设只侦听失效事件(属性已更改但未重新计算,某种中间状态)是一种性能优势。

为此,您需要实现一个
ChangeListener
。只有当值变为无效时,才会执行
invalizationListener
。看

从以下的java文档:

ObservableValue生成两种类型的事件:更改事件和 失效事件。更改事件表示该值已更改 改变。如果当前值为,则生成失效事件 不再有效了。如果 ObservalEvalue支持延迟求值,因为对于 评估值不知道是否确实存在无效值 更改,直到重新计算因此,正在生成更改 事件需要立即评估,而失效事件可以 为渴望和懒惰的实现生成

我添加了一个简单的示例

public static void main(String[] args) {

    SimpleIntegerProperty one = new SimpleIntegerProperty(1);
    SimpleIntegerProperty two = new SimpleIntegerProperty(0);

    // the binding we are interested in
    NumberBinding sum = one.add(two);
    sum.addListener(observable -> System.out.println("invalidated"));

    // if you add a value change listener, the value will NOT be evaluated lazy anymore
    //sum.addListener((observable, oldValue, newValue) -> System.out.println("value changed from " + oldValue + " to " + newValue));

    // is valid, since nothing changed so far
    System.out.println("sum valid: " + sum.isValid());
    // will invalidate the sum binding
    two.set(1);
    one.set(2); // invalidation event NOT fired here!
    System.out.println("sum valid: " + sum.isValid());
    // will validate the sum binding, since it is calculated lazy when getting the value
    System.out.println("sum: " + sum.getValue());
    System.out.println("sum valid: " + sum.isValid());
}
使用
invalizationListener
的问题是,如果该值再次无效,您将不会收到更改通知,因为该值已经无效。为此,您必须使用更改侦听器

在属性上注册更改侦听器将禁用惰性评估,因此每次触发更改侦听器时都会触发失效事件


在我添加的示例中尝试一下。

如果您计划使用InvalizationListener,有两条规则需要记住

  • 确保您的侦听器可以被调用是没有问题的,即使没有发生任何更改
  • 如果你想让你的监听器为每一个发生的变化而被激发(通常这是监听器的目的),那么确保监听器调用它注册的可观察对象的getter
  • 否则,从以下位置切换到ChangeListener.

    只有当 其内容的状态从有效变为无效。就是多个, 行中的失效应仅生成一个失效事件

    这是一个很小的例子

    public class stackOverflowListenerQuestion extends Application {
    
        public static void main( String[] args ) {
            launch();
        }
    
    
        @Override
        public void start( Stage primaryStage ) throws Exception {
            IntegerProperty money  = new SimpleIntegerProperty(1);
            money.addListener(observable -> System.out.println("we should notify the listener"));
            money.set(10);
            money.set(20);
            money.set(30);
            System.out.println(money.getValue());
    
    
            IntegerProperty moreMoney  = new SimpleIntegerProperty(1);
            moreMoney.addListener(( observable, oldValue, newValue ) -> System.out.println("we should notify the listener very quickly"));
            moreMoney.set(100);
            moreMoney.set(200);
            moreMoney.set(300);
            System.out.println(moreMoney.getValue());
            Platform.exit();
        }
    }
    
    输出

    we should notify the listener
    30
    we should notify the listener very quickly
    we should notify the listener very quickly
    we should notify the listener very quickly
    300
    
    money
    属性关联的侦听器类型为
    invalizationlistener
    ,从输出中我们可以看到
    invalizationlistener
    ChangeListener
    之间的事件差异

    还有一个更详细的例子:

     public class InvalidationListener extends Application {
    
            public static void main( String[] args ) {
                launch();
            }
    
            @Override
            public void start( Stage primaryStage ) throws Exception {
                Person p1 = new Person();
                Person p2 = new Person();
                Person p3 = new Person();
    
                NumberBinding total = Bindings.add(p1.moneyProperty().add(p2.moneyProperty()), p3.moneyProperty());
                //to see the differences between InvalidationListener and ChangeListener, yous should test them separately and watch the printed result to understand.
    
              //  total.addListener(( observable, oldValue, newValue ) -> System.out.println("change event occurred, we should notify the listeners"));
                total.addListener(observable -> System.out.println("Invalidation occurred, we should notify the listeners but lazily"));
    
                p1.setMoney(100);
                System.out.println("total.isValid() = " + total.isValid());
                p2.setMoney(200);
                System.out.println("total.isValid() = " + total.isValid());
                p3.setMoney(200);
                System.out.println("total.isValid() = " + total.isValid());
                System.out.println("total = " + total.getValue());
                System.out.println("total.isValid() = " + total.isValid());
                p3.setMoney(150);
                System.out.println("total.isValid() = " + total.isValid());
                System.out.println("total = " + total.getValue());
                System.out.println("total.isValid() = " + total.isValid());
                Platform.exit();//shutdown the JavaFx Application Thread
            }
    
            static class Person{
                private IntegerProperty money = new SimpleIntegerProperty();
    
                public final int getMoney() {
                    return money.get();
                }
    
                public final void setMoney( int money ) {
                    this.money.set(money);
                }
    
                public IntegerProperty moneyProperty() {
                    return money;
                }
            }
        }
    
    使用
    ChangeListener
    时,只要发生更改,就会触发一个事件。使用
    invalizationlistener
    时,情况并非如此

    来自同一本书

    当属性的状态为 值首次从有效更改为无效。财产 JavaFx使用惰性计算。当无效属性变为无效时 同样,不会生成失效事件。无效的财产 在重新计算时变为有效,例如,通过调用其get() 或getValue()方法


    但是一个值在更改时不总是第一次变为无效吗?是的,但只有一次,直到再次验证它(通过调用属性的getter)。因此,如果多次设置该值,只会注意到该值的第一次更改,进一步的更改不会触发事件。这可能会有所帮助。谢谢,我已更新了该问题。