JavaFX绑定不传递值

时间:2018-01-18 10:44:13

标签: java javafx javafx-8

在过去,我使用以下支持类将现有的ObservableValue换成一个触发FX事件线程更改的内容......这样可以正常工作。

class AsyncBinding<T> implements ObservableValue<T> {
    private List<InvalidationListener> invalidationListeners = new ArrayList<>(1);
    private List<ChangeListener<? super T>> changeListeners = new ArrayList<>(1);
    private ObservableValue<T> original;
    private ChangeListener<T> changeListener;
    private InvalidationListener invalidationListener;
    public AsyncBinding(ObservableValue<T> original) {
        super();
        this.original = original;
        changeListener = (obs, oldValue, newValue) -> {
            Runnable job = () -> {
                for (ChangeListener<? super T> listener : changeListeners) {
                    listener.changed(obs, oldValue, newValue);
                }
            };
            Platform.runLater(job);
        };
        original.addListener(changeListener);
        invalidationListener = obs -> {
            Runnable job = () -> {
                for (InvalidationListener listener : invalidationListeners) {
                    listener.invalidated(obs);
                }
            };
            Platform.runLater(job);
        };
        original.addListener(invalidationListener);
    }
    @Override
    public void addListener(InvalidationListener arg0) {
        invalidationListeners.add(arg0);
    }
    @Override
    public void removeListener(InvalidationListener arg0) {
        invalidationListeners.remove(arg0);
    }
    @Override
    public void addListener(ChangeListener<? super T> arg0) {
        changeListeners.add(arg0);
    }
    @Override
    public void removeListener(ChangeListener<? super T> arg0) {
        changeListeners.remove(arg0);

    }
    @Override
    public T getValue() {
        return original.getValue();
    }
}

但是,如果它与中间StringBinding一起使用,则会停止更新。以下案例显示了不同的行为。我排除了垃圾收集。我只是在解释/理解不同的行为之后。

案例1 - 财产 - &gt;异步 - &gt;标签。工作正常。

public class Case1 extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    // hold references to prevent garbage collection...
    private AsyncBinding<String> asyncValue;

    @Override
    public void start(Stage primaryStage) throws Exception {
        Label label = new Label();
        primaryStage.setScene(new Scene(label));
        primaryStage.show();

        ObjectProperty<String> property = new SimpleObjectProperty<>();

        asyncValue = new AsyncBinding<>(property);

        label.textProperty().bind(asyncValue);

        new Thread(() -> {
            for (int i = 0; i < 1_000_000; i++) {
                property.set("a" + i);
            }
        }, "background").start();
    }
}
<案例2 - 案例 - &gt; string - &gt;异步 - &gt;标签。停止随机更新......
public class Case2 extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    // hold references to prevent garbage collection...
    private StringBinding stringBinding;
    private AsyncBinding<String> asyncValue;

    @Override
    public void start(Stage primaryStage) throws Exception {
        Label label = new Label();
        primaryStage.setScene(new Scene(label));
        primaryStage.show();

        ObjectProperty<String> property = new SimpleObjectProperty<>();

        stringBinding = Bindings.createStringBinding(() -> {
            return "b" + property.get();
        }, property);

        asyncValue = new AsyncBinding<>(stringBinding);

        label.textProperty().bind(asyncValue);

        new Thread(() -> {
            for (int i = 0; i < 1_000_000; i++) {
                property.set("a" + i);
            }
        }, "background").start();
    }
}
<案例3 - 案例 - &gt;异步 - &gt; string - &gt;标签。工作正常。
public class Case3 extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    // hold references to prevent garbage collection...
    private StringBinding stringBinding;
    private AsyncBinding<String> asyncValue;

    @Override
    public void start(Stage primaryStage) throws Exception {
        Label label = new Label();
        primaryStage.setScene(new Scene(label));
        primaryStage.show();

        ObjectProperty<String> property = new SimpleObjectProperty<>();

        asyncValue = new AsyncBinding<>(property);

        stringBinding = Bindings.createStringBinding(() -> {
            return "b" + property.get();
        }, asyncValue);

        label.textProperty().bind(stringBinding);

        new Thread(() -> {
            for (int i = 0; i < 1_000_000; i++) {
                property.set("a" + i);
            }
        }, "background").start();
    }
}

1 个答案:

答案 0 :(得分:1)

经过一些检查后,我发现问题似乎是因为java在一段时间后为后台线程创建了AsyncBinding.original绑定的本地副本。后台线程不断更新它的本地副本,但JavaFX应用程序线程的值保持不变。

要解决此问题,您可以使用ChangeListener中获得的值并将其指定给字段。请改为使用getValue方法返回此值:

// field with updated value on the javafx application thread
private T value;

public AsyncBinding(ObservableValue<T> original) {
    super();
    this.original = original;
    changeListener = (obs, oldValue, newValue) -> {
        Runnable job = () -> {
            value = newValue; // make sure the value on the application thread is the new value
            for (InvalidationListener listener : invalidationListeners) {
                listener.invalidated(obs);
            }
            for (ChangeListener<? super T> listener : changeListeners) {
                listener.changed(obs, oldValue, newValue);
            }
        };
        Platform.runLater(job);
    };
    original.addListener(changeListener);
}

...

@Override
public T getValue() {
    return value;
}

这种方式应该更新 最终 。这可能需要一段时间,因为您正在进行1000000次Platform.runLater次调用,这可能需要一段时间才能完成冻结应用程序,直到完成为止。