我一直在研究这个问题,但我仍然非常困惑。
有人能给我一个具体的例子,说明何时使用 Task
以及何时使用 Platform.runLater(Runnable);
?它们到底有什么区别?何时使用其中任何一个有黄金法则吗?
并且,如果我理解不正确,请纠正我,这两个“对象”不是一种在 GUI 中创建另一个线程(用于更新 GUI)的方法吗?
我一直在研究这个问题,但我仍然非常困惑。
有人能给我一个具体的例子,说明何时使用 Task
以及何时使用 Platform.runLater(Runnable);
?它们到底有什么区别?何时使用其中任何一个有黄金法则吗?
并且,如果我理解不正确,请纠正我,这两个“对象”不是一种在 GUI 中创建另一个线程(用于更新 GUI)的方法吗?
对于快速简单的操作,请使用Platform.runLater(...)
,对于复杂和大型操作,请使用Task
。
示例:为什么不能使用Platform.runLater(...)
进行长时间的计算(从以下引用中获取)。
问题:后台线程只是从0计数到100万,并在UI中更新进度条。
使用Platform.runLater(...)
的代码:
final ProgressBar bar = new ProgressBar();
new Thread(new Runnable() {
@Override public void run() {
for (int i = 1; i <= 1000000; i++) {
final int counter = i;
Platform.runLater(new Runnable() {
@Override public void run() {
bar.setProgress(counter / 1000000.0);
}
});
}
}).start();
这是一段可怕的代码,违背了自然法则(以及一般编程规范)。首先,看到这个双重嵌套的Runnables,你会失去大脑细胞。其次,它将用许多小的Runnables淹没事件队列——事实上有一百万个。显而易见,我们需要一些API来使编写后台工作人员并与UI进行通信更容易。
使用任务的代码:
Task task = new Task<Void>() {
@Override public Void call() {
static final int max = 1000000;
for (int i = 1; i <= max; i++) {
updateProgress(i, max);
}
return null;
}
};
ProgressBar bar = new ProgressBar();
bar.progressProperty().bind(task.progressProperty());
new Thread(task).start();
它没有前面代码所展示的任何缺陷
参考资料: JavaFX 2.0中的工作线程
Platform.runLater
:如果您需要从非GUI线程更新GUI组件,可以使用它将您的更新放入队列中,然后由GUI线程尽快处理。Task
实现了 Worker
接口,用于在GUI线程之外运行长时间任务(以避免冻结应用程序),但仍需要在某个阶段与GUI交互。如果您熟悉 Swing,则前者相当于 SwingUtilities.invokeLater
,后者则相当于 SwingWorker
的概念。
Task 的 javadoc 给出了许多示例,这些示例应该可以说明如何使用它们。您还可以参考并发教程。
Platform.runLater(new Runnable() {public void run() {updateYourGuiHere();}});
,其中updateYourGuiHere()是用于更新您的图形用户界面的方法。 - assylias现在它可以更改为lambda版本
@Override
public void actionPerformed(ActionEvent e) {
Platform.runLater(() -> {
try {
//an event with a button maybe
System.out.println("button is clicked");
} catch (IOException | COSVisitorException ex) {
Exceptions.printStackTrace(ex);
}
});
}
Platform.runLater(() -> progressBar.setProgress(X/Y));
。 - Taelsin使用明确的Platform.runLater()的一个原因可能是,您将UI中的属性绑定到了服务(result)属性。因此,如果您要更新绑定的服务属性,必须通过runLater()来完成。
在UI线程中,也称为JavaFX应用程序线程:
...
listView.itemsProperty().bind(myListService.resultProperty());
...
在服务实现(后台工作者)中:
...
Platform.runLater(() -> result.add("Element " + finalI));
...
() -> { // Code here }
,或者() -> runSingleThing();
。因此,上面的代码会大大压缩,并且看起来不那么累赘。答案仍然是完全有效的 :) - ManoDestra