JavaFX中的Platform.runLater和Task
我一直在做这方面的研究,但我仍然非常困惑,至less可以说。
任何人都可以给我一个具体的例子,何时使用Task
,何时使用Platform.runLater(Runnable);
? 究竟是什么区别? 什么时候使用这些方法是否有一条金科玉律?
还纠正我,如果我错了,但不是这两个“对象”的方式创build另一个线程内的GUI(用于更新graphics用户界面)的主线程?
使用Platform.runLater(...)
进行快速简单的操作,并使用Task
执行复杂的大操作。
-
Platform.runLater(...)
用例 -
Task
:Ensemble App中的任务示例的用例
示例:为什么我们不能使用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给出了许多应该说明如何使用它们的例子。 你也可以参考关于并发的教程 。
现在可以更改为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()的一个原因可能是你绑定了一个属性在ui中的一个服务(result)属性。 所以,如果你更新绑定的服务属性,你必须通过runLater()来做到这一点:
在UI线程中也被称为JavaFX应用程序线程:
... listView.itemsProperty().bind(myListService.resultProperty()); ...
在服务实施(后台工作):
... Platform.runLater(() -> result.add("Element " + finalI)); ...