Javafx从线程更新UI,而不直接调用Platform.runLater
现在有人说,不适合使用 Platform.runLater()
从非JavaFX线程更新UI和Oracle网站介绍一种使用绑定进行进度的方法条更新。在这里我想更新一个标签,所以这样编码:
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();
它可以工作。
知道是不够好还是有任何其他方式来考虑?
谢谢。
I want to know is it good enough or is there any other ways to consider? Thank you.
我认为这不是真的, code> Platform.runLater(...)从后台线程更新UI。有一些情况下,这是正确的事情,如显示在 任务
Javadocs 。当您编写多线程JavaFX应用程序时, javafx.concurrent
API提供的是一个更高级的接口,用于您通常需要的功能。这个包中的类是由具有许多多线程编程专业知识的人编写的,所以很可能他们已经解决了一般程序员可能不知道的细微之处。
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 the Task
Javadocs. What the javafx.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.
作为一个例子,虽然 updateMessage
最终最终调用 Platform.runLater(...)
,两者不完全等价。如果你尝试一个天真的调用 Platform.runLater(..)
:
As an example, while it is correct that updateMessage
eventually ends up calling Platform.runLater(...)
, the two are not completely equivalent. If you try the same thing with a naïve call to Platform.runLater(..)
:
// Don't do this! It will make the UI unresponsive:
Task task = new Task() {
@Override
protected Object call() throws Exception {
int i = 0;
while (true) {
Platform.runLater(() -> lblStatus.textProperty().set("Count "+i));
i++;
}
return null ;
}
};
Thread t = new Thread(task);
您的UI将变为(至少部分)无响应。原因是你在FX应用程序线程上安排了太多的 Runnable
,它没有时间做正常的工作(渲染UI,响应用户输入,等)。 updateMessage(...)
的实现被仔细写入以调节对 Platform.runLater(...)
(基本上将它们限制为每帧渲染一个)。该代码是有点棘手的实现:使用 javafx.concurrent
API在你的代码示例意味着你不必自己实现。
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 of updateMessage(...)
is carefully written to "throttle" the calls to Platform.runLater(...)
(it basically limits them to one per frame-rendering). That code is a little tricky to implement: using the javafx.concurrent
API as in your code example means you don't have to implement it yourself.
因此,对UI的更改必须始终在FX应用程序线程上进行,计划这些更改的方式是通过 Platform.runLater(...)
。实际上,您可以直接调用,或调用代码来调用它。然而,一些API方法包装对 Platform.runLater(...)
的调用以相当复杂的方式进行,当这些方法提供您需要的功能,你应该更喜欢那些自己打电话。
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 to Platform.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.