Runlater 和 JavaFX 中的任务

我一直在做这方面的研究,但我仍然非常困惑,至少可以说。

谁能给我一个具体的例子,什么时候使用 Task和什么时候使用 Platform.runLater(Runnable);?到底有什么区别?什么时候使用这些东西有什么金科玉律吗?

如果我错了也请纠正我,但这两个“对象”不是在 GUI (用于更新 GUI)的主线程内创建另一个线程的方法吗?

185280 次浏览
  • Platform.runLater: If you need to update a GUI component from a non-GUI thread, you can use that to put your update in a queue and it will be handled by the GUI thread as soon as possible.
  • Task implements the Worker interface which is used when you need to run a long task outside the GUI thread (to avoid freezing your application) but still need to interact with the GUI at some stage.

If you are familiar with Swing, the former is equivalent to SwingUtilities.invokeLater and the latter to the concept of SwingWorker.

The javadoc of Task gives many examples which should clarify how they can be used. You can also refer to the tutorial on concurrency.

Use Platform.runLater(...) for quick and simple operations and Task for complex and big operations .

Example: Why Can't we use Platform.runLater(...) for long calculations (Taken from below reference).

Problem: Background thread which just counts from 0 to 1 million and update progress bar in UI.

Code using 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();

This is a hideous hunk of code, a crime against nature (and programming in general). First, you’ll lose brain cells just looking at this double nesting of Runnables. Second, it is going to swamp the event queue with little Runnables — a million of them in fact. Clearly, we needed some API to make it easier to write background workers which then communicate back with the UI.

Code using Task :

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();

it suffers from none of the flaws exhibited in the previous code

Reference : Worker Threading in JavaFX 2.0

It can now be changed to lambda version

@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);
}
});
}

One reason to use an explicite Platform.runLater() could be that you bound a property in the ui to a service (result) property. So if you update the bound service property, you have to do this via runLater():

In UI thread also known as the JavaFX Application thread:

...
listView.itemsProperty().bind(myListService.resultProperty());
...

in Service implementation (background worker):

...
Platform.runLater(() -> result.add("Element " + finalI));
...