有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java有什么区别吗?SwingWorker#发布vs SwingUtilities#调用器

比方说,我们有一个长/重的任务,必须在后台运行,并将其进度或任何内容发布到GUI。我知道这种发布必须在事件调度线程上进行。这就是为什么我们在任务中使用SwingWorker

所以,我们所做的是这样的:

public class WorkerTest {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("test");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new FlowLayout());

            JLabel label = new JLabel();
            frame.add(label);
            startWorker(label);

            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        });
    }

    private static void startWorker(JLabel label) {
        new SwingWorker<Integer, Integer>() {

            @Override
            protected Integer doInBackground() throws Exception {
                for (int i = 0; i < 500; i++) {
                    publish(i);
                    Thread.sleep(500); //Simulate long task
                }
                return null;
            }

            @Override
            protected void process(List<Integer> chunks) {
                Integer integer = chunks.get(0);
                label.setText(String.valueOf(integer));
            }
        }.execute();
    }
}

我的问题是,上述内容与此有何不同:

private static void startWorker(JLabel label) {
    new SwingWorker<Integer, Integer>() {

        @Override
        protected Integer doInBackground() throws Exception {
            for (int i = 0; i < 500; i++) {
                int i2 = i;
                SwingUtilities.invokeLater(() -> {
                    label.setText(String.valueOf(i2));
                });
                Thread.sleep(500); //Simulate long task
            }
            return null;
        }

    }.execute();
}

在这两种情况下,GUI的更新label.setText()运行到事件调度线程。它们有什么不同

当然,问题也存在,为什么我应该对worker实现done()方法,而不是在doInBackground方法的末尾调用SwingUtilities.invokeLater?除了处理doInBackground方法中可能引发的异常之外


共 (1) 个答案

  1. # 1 楼答案

    查看类SwingWorker中的方法publish()javadoc

    Because the process method is invoked asynchronously on the Event Dispatch Thread multiple invocations to the publish method might occur before the process method is executed. For performance purposes all these invocations are coalesced into one invocation with concatenated arguments.

    根据问题中的代码,直接从方法doInBackground()调用SwingUtilities.invokeLater()不会执行合并。也许你能想出一个理由,为什么合并是必要的?另请参阅Tasks that Have Interim Results

    关于SwingWorker类中的done()方法,您也曾询问过,我再次向您推荐javadoc

    Executed on the Event Dispatch Thread after the doInBackground method is finished. The default implementation does nothing. Subclasses may override this method to perform completion actions on the Event Dispatch Thread. Note that you can query status inside the implementation of this method to determine the result of this task or whether this task has been cancelled.

    所以你不必重写方法done()。就我个人而言,我通常会在SwingWorker对象中添加一个属性侦听器,用于处理[SwingWorker]任务完成后需要执行的任务。当然,YMMV