我只关心一项财产是否已经改变,而不是新的价值。
注册InvalidationListener而不是ChangeListener是否有好处?
我假设对属性的更改首先会使属性失效并通知所有无效侦听器。只有在已注册更改侦听器或有人请求此属性时,该属性才会被“验证”/重新计算,并且所有更改侦听器都将使用新值进行更新。
由于我对实际值不感兴趣,我认为只侦听无效事件(属性已经更改,但没有重新计算,某种中间状态)是一种性能优势。
发布于 2017-07-15 10:41:31
为此您需要实现一个ChangeListener。只有当值无效时才执行InvalidationListener。见文档。
来自ObservableValue的java文档
ObservableValue生成两种类型的事件:更改事件和无效事件。更改事件表示值已更改。如果当前值不再有效,则生成无效事件。如果ObservableValue支持延迟计算,那么这种区别就变得很重要,因为对于一个被延迟计算的值,在重新计算它之前,我们不知道无效值是否真的发生了更改。由于这个原因,生成更改事件需要急切的评估,而对于急切和延迟的实现,无效事件可以生成。
我增加了一个简单的例子
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的问题是,如果值再次无效,将不会通知您更改,因为它已经无效了。为此,您必须使用更改监听器。
在属性上注册更改侦听器将禁用惰性评估,因此每次触发更改侦听器时都会触发无效事件。
在我添加的样本中尝试一下。
发布于 2019-12-17 18:56:50
来自书:
只有当其内容的状态从有效变为无效时,可观察到的事件才会产生无效事件。也就是说,一行中的多个失效应该只生成一个无效事件。
一个很小的例子可以证明
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()方法,它将变得有效。
发布于 2019-02-02 17:43:07
如果计划使用InvalidationListener,需要记住两条规则。
否则,切换到ChangeListener。
https://stackoverflow.com/questions/45117076
复制相似问题