有中期结果的任务

对于后台任务,在仍在运行时提供临时结果通常很有用。该任务可以通过调用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中定义的“线程安全”。这意味着我们可以省去publishprocess并直接从工作线程中设置文本字段。我们选择忽略此事实是为了提供SwingWorker临时结果的简单演示。