绑定StringProperty时出现多线程错误

bas*_*aad 7 java multithreading javafx javafx-8

我有一个关于多线程和StringProperty绑定的问题.

我有一个类CacheManager,其中包含一个Thread更新我的缓存与服务器上的更改.现在,我想通知文本和进度的百分比(这是一个LabelProgressBar在JavaFX中).我使用public static DoubleProperty,StringProperty为此,在CacheManager类中定义.我只是像这样绑定它:

progressBar.progressProperty().bind(CacheManager.progress);
someLabel.textProperty().bind(CacheManager.status);
Run Code Online (Sandbox Code Playgroud)

现在,在Updater线程中,我更新了这些Properties.有了DoubleProperty这个工作得很好,并且ProgressBar正显示出完美的进展.但是,更新Label状态(来自的文本StringProperty)会引发错误:java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-9

现在,我的问题是:为什么DoubleProperty工作正常,而StringProperty抛出错误?他们考虑多线程有什么区别?

任何关于重新设计的想法也欢迎,非常感谢任何帮助!

Jam*_*s_D 12

调用导致从FX应用程序线程以外的线程更改UI的代码是错误的,无论它是否抛出异常.如果您违反此规则,FX工具包会尽最大努力抛出异常,但在某些情况下,对性能的影响太大而无法执行检查.如果您创建这些绑定,则必须在FX应用程序线程上执行对您绑定的属性的任何后续更改.即,如果您在后台线程中运行,则必须使用以下代码更改属性:

Platform.runLater(() -> CacheManager.progress.set(...));
Run Code Online (Sandbox Code Playgroud)

Platform.runLater(() -> CacheManager.status.set(...));
Run Code Online (Sandbox Code Playgroud)

由于您可能不希望将服务代码绑定到JavaFX(通过Platform类),因此您可以考虑使用侦听器而不是绑定,并从侦听器调度更新:

CacheManager.progress.addListener((obs, oldValue, newValue) -> 
    Platform.runLater(() -> progressBar.setProgress(newValue.doubleValue())));
CacheManager.status.addListener((obs, oldStatus, newStatus) -> 
    Platform.runLater(() -> someLabel.setText(newStatus)));
Run Code Online (Sandbox Code Playgroud)

如果用这些侦听器替换绑定,则可以自由更新任何线程上的属性.

  • 这个答案基本上归结为"不要在UI中绑定属性"; 这真的是唯一的方法吗?这似乎是JavaFX设计中的一个明显缺陷 - 如果需要在UI线程上更改属性,那么应该是绑定代码在那里执行它的责任; 您不应该在UI线程上更改数据模型 (4认同)