我有这个代码:
public class Test {
public static void main(String [] args) {
ObservableList<Integer> l = FXCollections.observableArrayList();
l.add(1);
l.add(2);
l.add(3);
BooleanProperty isPlayable = new SimpleBooleanProperty();
isPlayable.bind(Bindings.createBooleanBinding(() ->
{
System.out.println("List has changed");
return l.contains(2);
},l
));
l.remove(1);
我不明白为什么这段代码只能显示“列表已更改”?它应该两次,一次在绑定中,然后在删除中,因为该列表是可观察的。为什么列表更改不影响boolean属性?
(我在长代码中遇到了一个更大的问题,但是这种情况说明了我对布尔型属性绑定的误解)
谢谢 !
最佳答案
从ObservableValue
的documentation(Binding
和Property
都继承自):
ObservableValue
的实现可能支持惰性求值,这意味着更改后不会立即重新计算该值,但是下次请求该值时会延迟进行计算。该库中的所有绑定和属性都支持惰性评估。
ObservableValue
生成两种类型的事件:更改事件和无效事件。更改事件指示值已更改。如果当前值不再有效,则会生成一个无效事件。如果ObservableValue
支持延迟求值,则这种区别就变得很重要,因为对于延迟求值的值,直到重新计算无效值,才知道该值是否真的发生了变化。因此,生成更改事件需要进行急切的评估,而对于急切和懒惰的实现可以生成无效事件。
此类的实现应努力生成尽可能少的事件,以避免在事件处理程序中浪费太多时间。当第一个失效事件发生时,该库中的实现将自己标记为无效。在重新计算其值并再次使其有效之前,它们不再生成无效事件。
可以将两种类型的侦听器附加到ObservableValue
:InvalidationListener
侦听无效事件,而ChangeListener
侦听更改事件。
重要说明:即使ChangeListener
的实现支持惰性求值,附加ObservableValue
也会强制执行急切的计算。
请注意,Property#bind
和Bindings#createXXXBinding
都在一个或多个依赖项上注册了InvalidationListener
,而不是ChangeListener
。
如您所见,核心JavaFX中的绑定和属性是惰性的。从ObservableList
删除元素后,您再也不会查询该值,因此永远不会重新计算该值。由于永远不会重新计算该值,因此不会再次调用您的Callable
。
我真的很惊讶您竟然只见过"List has changed"
。您的代码都不要求该值,因此我不会期望要计算该值。但是,从实现的角度来看,注册InvalidationListener
的行为看起来会导致ObservableValue
得到验证(即,查询值),而#bind
添加了InvalidationListener
。我不确定实现为什么要这样做,但是确实如此。