首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JavaFX InvalidationListener或ChangeListener

JavaFX InvalidationListener或ChangeListener
EN

Stack Overflow用户
提问于 2017-07-15 10:20:47
回答 3查看 7.7K关注 0票数 11

我只关心一项财产是否已经改变,而不是新的价值。

注册InvalidationListener而不是ChangeListener是否有好处?

我假设对属性的更改首先会使属性失效并通知所有无效侦听器。只有在已注册更改侦听器或有人请求此属性时,该属性才会被“验证”/重新计算,并且所有更改侦听器都将使用新值进行更新。

由于我对实际值不感兴趣,我认为只侦听无效事件(属性已经更改,但没有重新计算,某种中间状态)是一种性能优势。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-07-15 10:41:31

为此您需要实现一个ChangeListener。只有当值无效时才执行InvalidationListener。见文档

来自ObservableValue的java文档

ObservableValue生成两种类型的事件:更改事件和无效事件。更改事件表示值已更改。如果当前值不再有效,则生成无效事件。如果ObservableValue支持延迟计算,那么这种区别就变得很重要,因为对于一个被延迟计算的值,在重新计算它之前,我们不知道无效值是否真的发生了更改。由于这个原因,生成更改事件需要急切的评估,而对于急切和延迟的实现,无效事件可以生成。

我增加了一个简单的例子

代码语言:javascript
复制
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());
}

使用InvalidationListener的问题是,如果值再次无效,将不会通知您更改,因为它已经无效了。为此,您必须使用更改监听器。

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

在我添加的样本中尝试一下。

票数 17
EN

Stack Overflow用户

发布于 2019-12-17 18:56:50

来自

只有当其内容的状态从有效变为无效时,可观察到的事件才会产生无效事件。也就是说,一行中的多个失效应该只生成一个无效事件。

一个很小的例子可以证明

代码语言:javascript
复制
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();
    }
}

输出

代码语言:javascript
复制
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属性关联的侦听器类型为Invalidationlistener,从输出中我们可以看到InvalidationListenerChangeListener在事件方面的差异。

还有一个更详细的例子:

代码语言:javascript
复制
 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时,每当发生更改时,都会触发事件。当您使用InvalidationListener时,情况并非如此。

从同一本书里

当属性的值状态第一次从有效变为无效时,该属性将生成无效事件。JavaFx中的属性使用惰性计算。当无效属性再次无效时,将不会生成无效事件。当重新计算无效属性时,例如通过调用它的get()或getValue()方法,它将变得有效。

票数 5
EN

Stack Overflow用户

发布于 2019-02-02 17:43:07

如果计划使用InvalidationListener,需要记住两条规则。

  1. 确保您的侦听器可以被调用是没有问题的,即使没有发生任何更改。
  2. 如果希望为发生的每一项更改(通常是侦听器的目的)而激发侦听器,请确保侦听器调用可观察到的对象的getter(s),并在其中注册它。

否则,切换到ChangeListener。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45117076

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档