绑定StringProperty时出现多线程错误 [英] Multi-Threading error when binding a StringProperty
问题描述
我有一个关于多线程和StringProperty绑定的问题。
I have a question about multi-threading and the binding of a StringProperty.
我有一个类 CacheManager
,包含 Thread
,它使用服务器上的更改更新我的缓存。现在,我想通知文本和进度百分比(这是一个标签
和 ProgressBar
JavaFX的)。我为此使用公共静态 DoubleProperty
和 StringProperty
,它们在 CacheManager中定义
class。我只是像这样绑定它:
I have a class CacheManager
, which contains a Thread
which updates my cache with the changes on the server. Now, I want to notify the user with a text and percentage of the progress (which are a Label
and ProgressBar
in JavaFX). I use public static DoubleProperty
and StringProperty
for this, which are defined in the CacheManager
class. I just bind it like this:
progressBar.progressProperty().bind(CacheManager.progress);
someLabel.textProperty().bind(CacheManager.status);
现在,在Updater线程中,我更新了这些属性
。使用 DoubleProperty
这很好用, ProgressBar
正在完美地显示进度。但是,使用状态(来自 StringProperty
的文本)更新 Label
会引发错误: java.lang.IllegalStateException:不在FX应用程序线程上; currentThread = Thread-9
Now, in the Updater thread, I update these Properties
. With DoubleProperty
this works just fine, and the ProgressBar
is showing the progress perfectly. However, updating the Label
with the status (which is the text from the StringProperty
) throws an error: java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-9
现在,我的问题是:为什么 DoubleProperty
工作正常,而 StringProperty
会引发错误?他们考虑多线程有什么区别?
Now, my question is: Why does the DoubleProperty
work just fine, while the StringProperty
throws an error? What is the difference between them considering multi-threading?
任何有关重新设计的想法也欢迎,非常感谢任何帮助!
Any ideas on a redesign are also welcome and any help is greatly appreciated!
推荐答案
调用导致从FX应用程序线程以外的线程更改UI的代码是错误的,无论是否或不会抛出异常。如果您违反此规则,FX工具包会尽最大努力抛出异常,但在某些情况下,对性能的影响太大而无法执行检查。如果您创建了这些绑定,则必须在FX应用程序线程上执行对绑定到的属性的任何后续更改。即,如果您在后台线程中运行,则必须使用以下代码更改属性:
It is wrong to call code that results in changes to the UI from a thread other than the FX Application Thread, regardless of whether or not it throws an exception. The FX toolkit makes a best effort to throw an exception if you violate this rule, but in some cases the effect on performance is too great to perform the check. If you create these bindings, then any subsequent changes to the properties to which you have bound must be executed on the FX Application Thread. I.e., if you are running in a background thread, you must change the properties with code like:
Platform.runLater(() -> CacheManager.progress.set(...));
和
Platform.runLater(() -> CacheManager.status.set(...));
因为您可能不希望将服务代码绑定到JavaFX(通过 Platform
class),您可以考虑使用侦听器而不是绑定,并从侦听器安排更新:
Since you probably don't want your service code to be tied to JavaFX (via the Platform
class), you could consider using listeners instead of bindings, and scheduling the updates from the listeners:
CacheManager.progress.addListener((obs, oldValue, newValue) ->
Platform.runLater(() -> progressBar.setProgress(newValue.doubleValue())));
CacheManager.status.addListener((obs, oldStatus, newStatus) ->
Platform.runLater(() -> someLabel.setText(newStatus)));
如果用这些侦听器替换绑定,则可以自由更新任何线程上的属性。
If you replace the bindings with these listeners, then you are free to update the properties on any thread.
这篇关于绑定StringProperty时出现多线程错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!