我有一个关于多线程和StringProperty绑定的问题。
我有一个类CacheManager
,其中包含一个Thread
,它使用服务器上的更改来更新我的缓存。现在,我想通知文本和进度百分比(在JavaFX中为Label
和ProgressBar
)。我为此使用公共静态DoubleProperty
和StringProperty
,它们在CacheManager
类中定义。我只是这样绑定它:
progressBar.progressProperty().bind(CacheManager.progress);
someLabel.textProperty().bind(CacheManager.status);
现在,在Updater线程中,我更新了这些Properties
。使用DoubleProperty
这很好用,ProgressBar
完美展示了进度。但是,使用状态(Label
中的文本)更新StringProperty
会引发错误:java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-9
现在,我的问题是:为什么DoubleProperty
工作得很好,而StringProperty
会引发错误?他们考虑多线程有什么区别?
欢迎任何关于重新设计的想法,非常感谢任何帮助!
答案 0 :(得分:11)
调用导致从FX应用程序线程以外的线程更改UI的代码是错误的,无论它是否抛出异常。如果您违反此规则,FX工具包会尽最大努力抛出异常,但在某些情况下,对性能的影响太大而无法执行检查。如果您创建了这些绑定,则必须在FX应用程序线程上执行对绑定到的属性的任何后续更改。即,如果您在后台线程中运行,则必须使用以下代码更改属性:
Platform.runLater(() -> CacheManager.progress.set(...));
和
Platform.runLater(() -> CacheManager.status.set(...));
由于您可能不希望将服务代码绑定到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)));
如果用这些侦听器替换绑定,则可以自由更新任何线程上的属性。