Nowadays some says it is not suitable to use Platform.runLater()
for updating the UI from a non-JavaFX Thread and Oracle site introduce a way with bindings for progress bar updating. Here I want to update a Label, so coded it like this:
Task task = new Task() {
@Override
protected Object call() throws Exception {
int i = 0;
while (true) {
this.updateMessage("Count " + i);
System.out.println(i);
// Thread.sleep(10);
i++;
}
}
};
Thread t = new Thread(task);
lbStatus.textProperty().bind(task.messageProperty());
t.start();
It works.
I want to know is it good enough or is there any other ways to consider? Thank you.
I don't think it's quite true to say it's not "suitable" to use
Platform.runLater(...)
to update the UI from a background thread. There are certainly cases where that is the correct thing to do, as shown in theTask
Javadocs. What thejavafx.concurrent
API provides is a "higher-level" interface to the functionality you commonly need when you are writing multithreaded JavaFX applications. The classes in this package are written by people with a lot of expertise in multithreaded programming, so it's likely that they have accounted for subtleties that the average programmer may not be aware of.As an example, while it is correct that
updateMessage
eventually ends up callingPlatform.runLater(...)
, the two are not completely equivalent. If you try the same thing with a naïve call toPlatform.runLater(..)
:your UI will become (at least partially) unresponsive. The reason is that you're scheduling so many
Runnable
s on the FX Application thread, it doesn't have time to do its regular work (rendering UI, responding to user input, etc). The implementation ofupdateMessage(...)
is carefully written to "throttle" the calls toPlatform.runLater(...)
(it basically limits them to one per frame-rendering). That code is a little tricky to implement: using thejavafx.concurrent
API as in your code example means you don't have to implement it yourself.So changes to the UI must always be made on the FX Application Thread, and the way to schedule those changes is via
Platform.runLater(...)
. In effect you either call that directly, or call code that ends up calling it. However, some of the API methods that wrap the calls toPlatform.runLater(...)
do so in quite sophisticated ways, and when those methods provide the functionality you need, you should probably prefer those to making the calls yourself.