These constraints mean that a GUI application with time intensive computing needs at least two threads: 1) a thread to perform the lengthy task and 2) the Event Dispatch Thread (EDT) for all GUI-related activities. This involves inter-thread communication which can be tricky to implement.
{@code SwingWorker} is designed for situations where you need to have a long running task run in a background thread and provide updates to the UI either when done, or while processing. Subclasses of {@code SwingWorker} must implement the {@see #doInBackground} method to perform the background computation.
Workflow
There are three threads involved in the life cycle of a {@code SwingWorker} :
Current thread: The {@link #execute} method iscalled on this thread. It schedules {@code SwingWorker} for the execution on aworker thread and returns immediately. One can wait for the {@code SwingWorker} tocomplete using the {@link #get get} methods.
Worker thread: The {@link #doInBackground} method is called on this thread. This is where all background activities should happen. To notify {@code PropertyChangeListeners} about bound properties changes use the{@link #firePropertyChange firePropertyChange} and{@link #getPropertyChangeSupport} methods. By default there are two boundproperties available: {@code state} and {@code progress}.
Event Dispatch Thread: All Swing related activities occur on this thread. {@code SwingWorker} invokes the{@link #process process} and {@link #done} methods and notifiesany {@code PropertyChangeListeners} on this thread.
Often, the Current thread is the Event Dispatch Thread.
Before the {@code doInBackground} method is invoked on a worker thread,{@code SwingWorker} notifies any {@code PropertyChangeListeners} about the{@code state} property change to {@code StateValue.STARTED}. After the {@code doInBackground} method is finished the {@code done} method isexecuted. Then {@code SwingWorker} notifies any {@code PropertyChangeListeners}about the {@code state} property change to {@code StateValue.DONE}.
{@code SwingWorker} is only designed to be executed once. Executing a{@code SwingWorker} more than once will not result in invoking the{@code doInBackground} method twice.
Sample Usage
The following example illustrates the simplest use case. Some processing is done in the background and when done you update a Swing component.
Say we want to find the "Meaning of Life" and display the result in a {@code JLabel}.
final JLabel label; class MeaningOfLifeFinder extends SwingWorker<String, Object> { {@code @Override}public String doInBackground() { return findTheMeaningOfLife(); } {@code @Override}protected void done() { try { label.setText(get()); } catch (Exception ignore) { } } } (new MeaningOfLifeFinder()).execute();
The next example is useful in situations where you wish to process data as it is ready on the Event Dispatch Thread.
Now we want to find the first N prime numbers and display the results in a {@code JTextArea}. While this is computing, we want to update our progress in a {@code JProgressBar}. Finally, we also want to print the prime numbers to {@code System.out}.
class PrimeNumbersTask extends SwingWorker<List<Integer>, Integer> { PrimeNumbersTask(JTextArea textArea, int numbersToFind) { //initialize } {@code @Override}public List<Integer> doInBackground() { while (! enough && ! isCancelled()) { number = nextPrimeNumber(); publish(number); setProgress(100 * numbers.size() / numbersToFind); } } return numbers; } {@code @Override}protected void process(List<Integer> chunks) { for (int number : chunks) { textArea.append(number + "\n"); } } } JTextArea textArea = new JTextArea(); final JProgressBar progressBar = new JProgressBar(0, 100); PrimeNumbersTask task = new PrimeNumbersTask(textArea, N); task.addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { progressBar.setValue((Integer)evt.getNewValue()); } } }); task.execute(); System.out.println(task.get()); //prints all prime numbers we have got
Because {@code SwingWorker} implements {@code Runnable}, a {@code SwingWorker} can be submitted to an{@link java.util.concurrent.Executor} for execution. @author Igor Kushnirskiy @version $Revision: 1.6 $ $Date: 2008/07/25 19:32:29 $ @param < T> the result type returned by this {@code SwingWorker's}{@code doInBackground} and {@code get} methods @param < V> the type used for carrying out intermediate results by this{@code SwingWorker's} {@code publish} and {@code process} methods
|
|
|
|