我有这个代码:

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属性?

(我在长代码中遇到了一个更大的问题,但是这种情况说明了我对布尔型属性绑定的误解)

谢谢 !

最佳答案

ObservableValuedocumentationBindingProperty都继承自):


  ObservableValue的实现可能支持惰性求值,这意味着更改后不会立即重新计算该值,但是下次请求该值时会延迟进行计算。该库中的所有绑定和属性都支持惰性评估。
  
  ObservableValue生成两种类型的事件:更改事件和无效事件。更改事件指示值已更改。如果当前值不再有效,则会生成一个无效事件。如果ObservableValue支持延迟求值,则这种区别就变得很重要,因为对于延迟求值的值,直到重新计算无效值,才知道该值是否真的发生了变化。因此,生成更改事件需要进行急切的评估,而对于急切和懒惰的实现可以生成无效事件。
  
  此类的实现应努力生成尽可能少的事件,以避免在事件处理程序中浪费太多时间。当第一个失效事件发生时,该库中的实现将自己标记为无效。在重新计算其值并再次使其有效之前,它们不再生成无效事件。
  
  可以将两种类型的侦听器附加到ObservableValueInvalidationListener侦听无效事件,而ChangeListener侦听更改事件。
  
  重要说明:即使ChangeListener的实现支持惰性求值,附加ObservableValue也会强制执行急切的计算。


请注意,Property#bindBindings#createXXXBinding都在一个或多个依赖项上注册了InvalidationListener,而不是ChangeListener

如您所见,核心JavaFX中的绑定和属性是惰性的。从ObservableList删除元素后,您再也不会查询该值,因此永远不会重新计算该值。由于永远不会重新计算该值,因此不会再次调用您的Callable

我真的很惊讶您竟然只见过"List has changed"。您的代码都不要求该值,因此我不会期望要计算该值。但是,从实现的角度来看,注册InvalidationListener的行为看起来会导致ObservableValue得到验证(即,查询值),而#bind添加了InvalidationListener。我不确定实现为什么要这样做,但是确实如此。

07-22 00:26