有中期结果的任务
对于后台任务,在仍在运行时提供临时结果通常很有用。该任务可以通过调用SwingWorker.publish来完成。此方法接受可变数量的参数。每个参数必须是SwingWorker
的第二个类型参数指定的类型。
要收集publish
提供的结果,请覆盖SwingWorker.process,该方法将从事件分配线程中调用。来自publish
的多次调用的结果通常是针对process
的一次调用而累积的。
让我们看看Flipper.java示例使用publish
提供临时结果的方式。单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行Flipper
。或者,要自己编译并运行示例,请参考example index。
该程序通过在后台任务中生成一系列随机的boolean
值来测试java.util.Random的公平性。这相当于掷硬币。因此名称为Flipper
。要报告其结果,后台任务使用类型为FlipPair
的对象
private static class FlipPair {
private final long heads, total;
FlipPair(long heads, long total) {
this.heads = heads;
this.total = total;
}
}
heads
字段是随机值已达到true
的次数; total
字段是随机值的总数。
后台任务由FlipTask
的实例表示:
private class FlipTask extends SwingWorker<Void, FlipPair> {
由于该任务不会返回final结果,因此第一类型参数是什么都没有关系。 Void
用作占位符。该任务在每次“掷硬币”之后调用publish
:
@Override
protected Void doInBackground() {
long heads = 0;
long total = 0;
Random random = new Random();
while (!isCancelled()) {
total++;
if (random.nextBoolean()) {
heads++;
}
publish(new FlipPair(heads, total));
}
return null;
}
(在下一节中将讨论isCancelled
方法.)由于publish
的调用非常频繁,因此在事件分配线程中调用process
之前,很可能会累积很多FlipPair
值; process
仅对每次报告的最后一个值感兴趣,使用它来更新 GUI:
protected void process(List<FlipPair> pairs) {
FlipPair pair = pairs.get(pairs.size() - 1);
headsText.setText(String.format("%d", pair.heads));
totalText.setText(String.format("%d", pair.total));
devText.setText(String.format("%.10g",
((double) pair.heads)/((double) pair.total) - 0.5));
}
如果Random
是公平的,则Flipper
运行时devText
中显示的值应越来越接近于 0.
Note:
Flipper
中使用的setText
方法实际上是其specification中定义的“线程安全”。这意味着我们可以省去publish
和process
并直接从工作线程中设置文本字段。我们选择忽略此事实是为了提供SwingWorker
临时结果的简单演示。