Is there any difference? SwingWorker#publish vs SwingUtilities#invokeLater

114 views Asked by At

Let's say we have a long/heavy task that must run in background, and publish its progress or whatever to the GUI. I know that this publishing must happen on the event dispatch thread. That's why we use a SwingWorker for the task.

So, what we do, is something like this:

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

My question is, how the above differs from this:

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

In both cases, the label.setText() which is an update to the GUI, runs to the Event dispatch thread. How are they different?

Of course, the question stands also why should I implement a done() method to the worker vs calling SwingUtilities.invokeLater at the end of the doInBackground method? Besides handling the exception possibly thrown in doInBackground method.

1

There are 1 answers

0
Abra On BEST ANSWER

Look at the javadoc for method publish() in class SwingWorker.

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.

Calling SwingUtilities.invokeLater() directly from method doInBackground() does not perform the coalescing – according to the code in your question. Perhaps you can think of a reason why the coalescing is necessary? Also refer to Tasks that Have Interim Results

Regarding method done() in class SwingWorker, that you also asked about, again I refer you to the 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.

So you don't have to override method done(). Personally, I usually add a property listener to my SwingWorker object for handling tasks that I need to perform once the [SwingWorker] task has completed. But of-course, YMMV.