我只对天气属性的变化感兴趣,但不是新值。
注册InvalidationListener
而不是ChangeListener
我假设,对属性的更改首先使属性失效并通知所有失效侦听器。只有在注册了更改侦听器或者有人请求此属性时,才会“验证”/重新计算该属性,并使用新值更新所有更改侦听器。
由于我对实际值不感兴趣,因此我认为仅监听失效事件(属性已更改但未重新计算,某种中间状态)是一种性能优势。
答案 0 :(得分:8)
您需要为此实施ChangeListener
。只有在值无效后才会执行InvalidationListener
。请参阅docs。
来自ObservableValue的java文档:
ObservableValue生成两种类型的事件:更改事件和 失效事件。更改事件表示该值具有 改变。如果当前值为,则生成失效事件 不再有效。如果这种区别变得很重要 ObservableValue支持延迟评估,因为懒惰 评估值1不知道无效值是否确实存在 改变,直到重新计算。 因此,产生变化 事件需要急切的评估,而失效事件可以 为急切和懒惰的实现而生成。
我添加了一个简单的例子
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
时遇到的问题是如果值再次失效,则不会收到更改通知,因为它已经无效。您必须使用更改侦听器。
在属性上注册更改侦听器将禁用延迟评估,因此每次更改侦听器被触发时都会触发invalidation事件。
在我添加的样本中尝试一下。
答案 1 :(得分:2)
来自book:
可观察对象仅应在以下情况下生成无效事件: 其内容的状态从有效变为无效。也就是说,多个 连续的失效应该只产生一个失效事件。
一个小例子来说明
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
属性关联的侦听器为Invalidationlistener
类型,从输出中我们可以看到InvalidationListener
和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
时,只要发生更改,就会触发一个事件。使用InvalidationListener
时并非如此。
来自同一本书
属性在其状态下会生成无效事件 值首次从有效更改为无效。中的属性 JavaFx使用惰性评估。当无效的属性变为无效时 同样,不会生成无效事件。无效的属性 重新计算时变为有效,例如,通过调用其get() 或getValue()方法。
答案 2 :(得分:0)
有两个规则要记住,如果你打算使用一个InvalidationListener。
否则切换到的ChangeListener。