Codementor Events

Intro to SwingWorker in Java

Published Aug 16, 2016Last updated Jan 18, 2017
Intro to SwingWorker in Java

SwingWorker Tutorial

When running a program that needs to execute a long-running task, we want to be able to allow the execution of the main application to continue while the work completes in the background. To do so, we use a SwingWorker, which allows creating a background thread to perform our task and communicate to our main application the progress.

Quick Notes About SwingWorker

  • The javax.swing.SwingWorker class was added to the Java platform in Java SE 6.
  • Prior to Java SE 6, another class, also called SwingWorker, was widely used for some of the same purposes. The old SwingWorker was not part of the Java platform specification, and was not provided as part of the JDK.

Anatomy of the SwingWorker

There are three threads involved in the life cycle of a SwingWorker:

  • Current thread: The execute() method is called on this thread. It schedules SwingWorker for the execution on a worker thread and returns immediately. One can wait for the SwingWorker to complete using the get methods.
  • Worker thread: The doInBackground() method is called on this thread. This is where all background activities should happen. To notify PropertyChangeListeners about bound properties changes use the firePropertyChange and getPropertyChangeSupport() methods. By default, there are two bound properties available: state and progress.
  • Event Dispatch Thread: All Swing related activities occur on this thread. SwingWorker invokes the process() and done() methods and notifies any PropertyChangeListeners on this thread.

When creating a SwingWorker<T, V>, we define two parameters on the constructor; T — the result type returned by this SwingWorker's doInBackground() and get() methods, and V the type used for carrying out intermediate results by this SwingWorker's publish() and process() methods.
The first parameter is used to inform the done() method of the result of the background execution, whereas the second parameter is sent to the process() method to have preliminary results displayed like in a UI.

Vacuous SwingWorker example:

SwingWorker worker = new SwingWorker<Boolean, Integer>() {
  @Override
  protected Boolean doInBackground() throws Exception {
    // Background work

    // Value transmitted to done()
    return true;
  }

  @Override
  protected void process(List<Integer> chunks) {
    // Process results
  }

  @Override
  protected void done() {
    // Finish sequence
  }
};

Hands-on SwingWorker Example

Now that the theoretical background of the SwingWorker has been covered, we will proceed with a practical example that will show how to find even numbers, while displaying the percentage of progress.

The doInBackground() method is in charge of executing the part of our code that will take a considerable amount of time to complete.
Inside this method, we have the following options to inform about the execution.

  1. setProgress(): Sets the percentage value of the overall progress.
  2. publish(): Sends a chunk of information to the process() method that can be retrieved to perform a task.
  3. return: When we finish or end in an inconsistent state, we can stop the background execution by returning the value to the done() method.

In our example, we find even numbers and send them to the process() method to print the findings. Once we finish, we send a boolean result to the done() method to write the obtained value.

To start the worker we call the method from the class Loader and we add a loop to detect if the worker has finished. If it has not finished we print the progress and wait a half second before checking again.

In the example, we have a waitFor() method to make the program take longer for didactic purpose.

Compiling the Example:

To compile the code from a terminal you just need to execute the javac compiler as shown below.

Swingworker

Executing the Example:

To execute the compiled code from the terminal, you just need to run the Java code as shown below. The example shows the expected output of the code.

Swingworker

Complete SwingWorker Example:

import javax.swing.*;
import java.util.List;

/**
 * Created by Isai B. Cicourel
 */
public class Loader {


    /**
     * Creates an Example SwingWorker
     */
    public SwingWorker createWorker() {
        return new SwingWorker<Boolean, Integer>() {
            @Override
            protected Boolean doInBackground() throws Exception {
                // Start Progress
                setProgress(0);
                waitFor(500);

                // Example Loop
                for (int iCount = 1; iCount <= 20; iCount++) {
                    // Is an even number?
                    if (iCount % 2 == 0) {
                        publish(iCount);
                    }

                    // Set Progress
                    setProgress((iCount * 100) / 20);
                    waitFor(250);
                }

                // Finished
                return true;
            }

            @Override
            protected void process(List<Integer> chunks) {
                // Get Info
                for (int number : chunks) {
                    System.out.println("Found even number: " + number);
                }
            }

            @Override
            protected void done() {
                boolean bStatus = false;
                try {
                    bStatus = get();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                System.out.println("Finished with status " + bStatus);
            }
        };
    } // End of Method: createWorker()


    /**
     * Wait the given time in milliseconds
     * @param iMillis
     */
    private void waitFor (int iMillis) {
        try {
            Thread.sleep(iMillis);
        }
        catch (Exception ex) {
            System.err.println(ex);
        }
    } // End of Method: waitFor()


    public static void main(String[] args) {
        // Create the worker
        Loader l = new Loader();
        SwingWorker work = l.createWorker();
        work.execute();

        // Wait for it to finish
        while (!work.isDone()) {
            // Show Progress
            try {
                int iProgress = work.getProgress();
                System.out.println("Progress %" + iProgress);
                Thread.sleep(500);
            }
            catch (Exception ex) {
                System.err.println(ex);
            }
        } // End of Loop: while (!work.isDone())
    } // End of: main()
    
    
} // End of Class definition

Discover and read more posts from Isai B. Cicourel
get started