【问题标题】:JavaFX Beans Binding suddenly stops workingJavaFX Beans Binding 突然停止工作
【发布时间】:2014-07-10 06:01:09
【问题描述】:

我使用 JavaFX NumberBindings 来计算某些值。最初一切都按预期工作。然而,在相当短的时间之后,绑定停止工作。我也没有收到异常。

我尝试了几种绑定,以及高级和低级方法。甚至计算本身(当被覆盖时)也会停止并且不再被调用。我还更新到最新的 JDK (1.8.0_05) 并重建/重新启动了一切。

以下最小工作示例说明了该问题。它应该将 System.out.println 主窗口的当前宽度转换为 STDOUT。调整窗口大小约 10 秒后,输出停止。我还尝试将生成的属性绑定到 JavaFX 控件,以确保该属性的继续使用,但这无济于事。我相信我在这里遗漏了属性/绑定的一些非常基本的行为,谷歌似乎根本不知道这种行为。

import javafx.application.Application;
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class BindingsProblem extends Application {

@Override
public void start(Stage primaryStage) {
    // Initialization...
    StackPane root = new StackPane();
    Scene scene = new Scene(root, 300, 250);
    primaryStage.setScene(scene);
    primaryStage.show();


    // Binding - The problem occurrs here!
    NumberBinding currentWidthPlusTen = primaryStage.widthProperty().add(10);
    IntegerProperty boundNumberProperty = new SimpleIntegerProperty();
    boundNumberProperty.bind(currentWidthPlusTen);
    boundNumberProperty.addListener(new ChangeListener<Number>() {

        @Override
        public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
            System.out.println(newValue.toString());
        }

    });
}


public static void main(String[] args) {
    launch(args);
}

}

【问题讨论】:

  • 我可以重现该问题。它看起来像一个错误。你在 jira 上搜索过吗?
  • 我似乎找不到现有的错误报告。它看起来很基础,很难想象它是 JDK/JRE 本身的错误。

标签: java binding properties javafx javabeans


【解决方案1】:

绑定使用WeakListener 来观察currentWidthPlusTen 的值。由于您没有保留对boundNumberProperty 的引用,因此只要start(...) 方法退出,它就有资格进行垃圾收集。当垃圾收集器启动时,引用完全丢失,绑定不再起作用。

要直接查看,请添加行

root.setOnMousePressed( event -> System.gc());

start(...) 方法。您可以通过单击窗口来强制监听器“停止工作”。

显然,这不是您想要的:解决方法是在 start(...) 退出后保留对 boundNumberProperty 的引用。例如:

import javafx.application.Application;
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class BindingsProblem extends Application {

    IntegerProperty boundNumberProperty;

    @Override
    public void start(Stage primaryStage) {
        // Initialization...
        StackPane root = new StackPane();
        Scene scene = new Scene(root, 300, 250);
        primaryStage.setScene(scene);
        primaryStage.show();

        // Binding - The problem occurrs here!
        NumberBinding currentWidthPlusTen = primaryStage.widthProperty()
                .add(10);

        boundNumberProperty = new SimpleIntegerProperty();
        boundNumberProperty.bind(currentWidthPlusTen);
        boundNumberProperty.addListener(new ChangeListener<Number>() {

            @Override
            public void changed(ObservableValue<? extends Number> observable,
                    Number oldValue, Number newValue) {
                System.out.println(newValue.toString());
            }

        });

    }

    public static void main(String[] args) {
        launch(args);
    }

}

更新

遇到此问题的任何人可能还想查看 Tomas Mikula 的 ReactFX,它为此提供了更简洁的解决方法(以使用第三方库为代价,您需要花一些时间学习)。 Tomas 在 this blogsubsequent post 中解释了这个问题以及 ReactFX 如何解决它。

【讨论】:

  • 非常好!这解决了我的问题。我倾向于信任并依赖 Java 中的自动内存/引用管理。显然太多了:D
  • 有趣的是,大多数情况下,除了示例代码中的简单测试类型之外,您实际上将它用于任何实际的事情,问题就消失了。例如,如果您创建一个标签并将其文本绑定到您的IntegerProperty,那么该标签当然会有效地保留对该属性的引用,因此它不会被垃圾收集。这个问题只是偶尔会在真实场景中出现,但非常罕见。
  • 这个问题让我发疯了,因为我在 2.x 中工作的大量代码现在“神秘地”停止工作。希望至少可以控制何时使用WeakListeners...
猜你喜欢
  • 2017-08-22
  • 2021-02-01
  • 2016-12-29
  • 2018-05-09
  • 2015-12-07
  • 2015-08-23
  • 2014-02-05
  • 2013-09-06
相关资源
最近更新 更多