Multithreading error while binding StringProperty

I have a question about multithreading and StringProperty binding.

I have a CacheManager class that contains a Thread that updates my cache with changes on the server. Now I want to notify the user with text and percentage of progress (which are Label and ProgressBar in JavaFX). To do this, I use the public static DoubleProperty and StringProperty , which are defined in the CacheManager class. I just bind it like this:

 progressBar.progressProperty().bind(CacheManager.progress); someLabel.textProperty().bind(CacheManager.status); 

Now, in the Updater thread, I am updating these Properties . With DoubleProperty this works great, and the ProgressBar shows progress very well. However, updating a Label with a status (which is the text from StringProperty ) raises an error: java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-9 java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-9

Now, my question is: Why does DoubleProperty work, and StringProperty error? What is the difference between the two when considering multithreading?

Any redesign ideas are also welcome, and any help is much appreciated!

+6
source share
1 answer

It is incorrect to call code that leads to changes in the user interface from a thread other than the FX application thread, regardless of whether it throws an exception. The FX toolkit does its best to throw an exception if you violate this rule, but in some cases the performance impact is too great to run the test. If you create these bindings, any subsequent changes to the properties to which you are bound must be made in the FX application thread. Ie, if you are working in a background thread, you must change the properties using code, for example:

 Platform.runLater(() -> CacheManager.progress.set(...)); 

and

 Platform.runLater(() -> CacheManager.status.set(...)); 

Since you probably don't want your service code to bind to JavaFX (via the Platform class), you might consider using listeners instead of bindings and scheduling updates from 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, you can update the properties in any thread.

+10
source

Source: https://habr.com/ru/post/989191/


All Articles