You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX带提取器的ObservableList行为异常:依赖属性监听器存在性

OpenJFX 21 ObservableList提取器仅触发一次更新的Bug分析与临时解决

问题确认

这是OpenJFX 21的已知Bug,并非代码逻辑问题。当ObservableList提取器关联的属性未额外绑定ChangeListener时,提取器只会触发一次元素更新通知;添加空的ChangeListener后,通知机制恢复正常。

最小复现代码

TestClass.java

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class TestClass {
    private final StringProperty name = new SimpleStringProperty();

    public TestClass() {
        new Thread(() -> {
            int count = 0;
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
                setName("Name " + count++);
            }
        }).start();
    }

    public String getName() {
        return name.get();
    }

    public StringProperty nameProperty() {
        return name;
    }

    public void setName(String name) {
        this.name.set(name);
    }
}

主程序

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.stage.Stage;

public class MainApp extends Application {
    @Override
    public void start(Stage primaryStage) {
        ObservableList<TestClass> list = FXCollections.observableArrayList(
                item -> new javafx.beans.Observable[]{item.nameProperty()}
        );

        TestClass testItem = new TestClass();
        list.add(testItem);

        // 注释此行:列表仅触发一次更新;取消注释:持续触发更新
        // testItem.nameProperty().addListener((obs, oldVal, newVal) -> {});

        list.addListener((ListChangeListener<TestClass>) change -> {
            while (change.next()) {
                if (change.wasUpdated()) {
                    System.out.println("List element was updated");
                }
            }
        });
    }

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

现象分析

  • 未添加空ChangeListener:ObservableList仅在第一次修改nameProperty时输出预期内容,后续属性变更不再触发列表更新通知。
  • 添加空ChangeListener:每次修改nameProperty都会触发列表的更新通知,持续输出"List element was updated"。

临时解决办法

给关联的属性添加一个空的ChangeListener即可绕过该Bug。原因是OpenJFX内部对属性通知机制存在优化逻辑:当属性仅绑定了提取器的监听器时,第一次通知后可能会停止后续的无效化通知;额外添加一个Listener会强制保持通知机制的正常运行。

内容的提问来源于stack exchange,提问作者Stefan Pfeifer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 00:29:58