|
JavaTM Platform Standard Ed. 6 |
|||||||||
| 上一个类 下一个类 | 框架 无框架 | |||||||||
| 摘要: 嵌套 | 字段 | 构造方法 | 方法 | 详细信息: 字段 | 构造方法 | 方法 | |||||||||
java.lang.Objectjavax.swing.SwingWorker<T,V>
T - 此 SwingWorker 的 doInBackground 和 get 方法返回的结果类型V - 用于保存此 SwingWorker 的 publish 和 process 方法的中间结果的类型public abstract class SwingWorker<T,V>
在专用线程中执行长时间 GUI 交互任务的抽象类。
使用 Swing 编写多线程应用程序时,要记住两个约束条件:(有关详细信息,请参阅 How to Use Threads):
这些约束意味着需要时间密集计算操作的 GUI 应用程序至少需要以下两个线程:1) 执行长时间任务的线程; 2) 所有 GUI 相关活动的事件指派线程 (EDT)这涉及到难以实现的线程间通信。
SwingWorker 设计用于需要在后台线程中运行长时间运行任务的情况,并可在完成后或者在处理过程中向 UI 提供更新。SwingWorker 的子类必须实现 doInBackground() 方法,以执行后台计算。
工作流
SwingWorker 的生命周期中包含三个线程:
当前 线程:在此线程上调用 execute() 方法。它调度 SwingWorker 以在 worker 线程上执行并立即返回。可以使用 get 方法等待 SwingWorker 完成。
Worker 线程:在此线程上调用 doInBackground() 方法。所有后台活动都应该在此线程上发生。要通知 PropertyChangeListeners 有关绑定 (bound) 属性的更改,请使用 firePropertyChange 和 getPropertyChangeSupport() 方法。默认情况下,有两个可用的绑定属性:state 和 progress。
事件指派线程:所有与 Swing 有关的活动都在此线程上发生。SwingWorker 调用 process 和 done() 方法,并通知此线程的所有 PropertyChangeListener。
通常,当前 线程就是事件指派线程。
在 worker 线程上调用 doInBackground 方法之前,SwingWorker 通知所有 PropertyChangeListener 有关对 StateValue.STARTED 的 state 属性更改。doInBackground 方法完成后,执行 done 方法。然后 SwingWorker 通知所有 PropertyChangeListener 有关对 StateValue.DONE 的 state 属性更改。
SwingWorker 被设计为只执行一次。多次执行 SwingWorker 将不会调用两次 doInBackground 方法。
示例用法
下例说明了最简单的使用范例:在后台完成某些处理,并在处理完成后更新 Swing 组件。
假定想找到“Meaning of Life”并在 JLabel 中显示结果。
final JLabel label;
class MeaningOfLifeFinder extends SwingWorker<String, Object> {
@Override
public String doInBackground() {
return findTheMeaningOfLife();
}
@Override
protected void done() {
try {
label.setText(get());
} catch (Exception ignore) {
}
}
}
(new MeaningOfLifeFinder()).execute();
在希望处理已经在事件指派线程 上准备好的数据时,下一个例子很有用。
现在想要查找第一个 N 素数值并在 JTextArea 中显示结果。在计算过程中,想在 JProgressBar 中更新进度。最后,还要将该素数值打印到 System.out。
class PrimeNumbersTask extends
SwingWorker<List<Integer>, Integer> {
PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
//initialize
}
@Override
public List<Integer> doInBackground() {
while (! enough && ! isCancelled()) {
number = nextPrimeNumber();
publish(number);
setProgress(100 * numbers.size() / numbersToFind);
}
}
return numbers;
}
@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
因为 SwingWorker 实现了 Runnable,所以可以将 SwingWorker 提交给 Executor 执行。
| 嵌套类摘要 | |
|---|---|
static class |
SwingWorker.StateValue
state 绑定 (bound) 属性的值。 |
| 构造方法摘要 | |
|---|---|
SwingWorker()
构造此 SwingWorker。 |
|
| 方法摘要 | |
|---|---|
void |
addPropertyChangeListener(PropertyChangeListener listener)
将 PropertyChangeListener 添加到侦听器列表。 |
boolean |
cancel(boolean mayInterruptIfRunning)
试图取消对此任务的执行。 |
protected abstract T |
doInBackground()
计算结果;如果无法计算结果,则抛出异常。 |
protected void |
done()
doInBackground 方法完成后,在事件指派线程 上执行此方法。 |
void |
execute()
调度此 SwingWorker 以便在 worker 线程上执行。 |
void |
firePropertyChange(String propertyName,
Object oldValue,
Object newValue)
向所有已注册的侦听器报告绑定属性更新。 |
T |
get()
如有必要,等待计算完成,然后获取其结果。 |
T |
get(long timeout,
TimeUnit unit)
如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。 |
int |
getProgress()
返回 progress 绑定属性。 |
PropertyChangeSupport |
getPropertyChangeSupport()
返回此 SwingWorker 的 PropertyChangeSupport。 |
SwingWorker.StateValue |
getState()
返回 SwingWorker 状态绑定属性。 |
boolean |
isCancelled()
如果在任务正常完成前将其取消,则返回 true。 |
boolean |
isDone()
如果任务已完成,则返回 true。 |
protected void |
process(List<V> chunks)
在事件指派线程 上异步地从 publish 方法接收数据块。 |
protected void |
publish(V... chunks)
将数据块发送给 process(java.util.List 方法。 |
void |
removePropertyChangeListener(PropertyChangeListener listener)
从侦听器列表中移除一个 PropertyChangeListener。 |
void |
run()
将此 Future 设置为计算的结果,除非它已经被取消。 |
protected void |
setProgress(int progress)
设置 progress 绑定属性。 |
| 从类 java.lang.Object 继承的方法 |
|---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| 构造方法详细信息 |
|---|
public SwingWorker()
SwingWorker。
| 方法详细信息 |
|---|
protected abstract T doInBackground()
throws Exception
注意,此方法只执行一次。
注:此方法在后台线程中执行。
Exception - 如果无法计算结果public final void run()
Future 设置为计算的结果,除非它已经被取消。
Runnable 中的 runRunnableFuture<T> 中的 runThread.run()protected final void publish(V... chunks)
process(java.util.List) 方法。将从 doInBackground 方法内部使用此方法传送中间结果,以便在 process 方法内部对事件指派线程 进行处理。
由于在事件指派进程 上异步地调用 process 方法,所以在执行 process 方法之前可以对 publish 方法进行多次调用。为了改进性能,所有这些调用都合并为一个带连接参数的调用。
例如:
publish("1");
publish("2", "3");
publish("4", "5", "6");
结果可能为:
process("1", "2", "3", "4", "5", "6")
示例用法。以下代码片断加载某一表格数据,并用它来更新 DefaultTableModel。注意,从 process 方法内部更换 tableModel 是安全的,因为该方法是在事件指派线程 上调用的。
class TableSwingWorker extends
SwingWorker<DefaultTableModel, Object[]> {
private final DefaultTableModel tableModel;
public TableSwingWorker(DefaultTableModel tableModel) {
this.tableModel = tableModel;
}
@Override
protected DefaultTableModel doInBackground() throws Exception {
for (Object[] row = loadData();
! isCancelled() && row != null;
row = loadData()) {
publish((Object[]) row);
}
return tableModel;
}
@Override
protected void process(List<Object[]> chunks) {
for (Object[] row :chunks) {
tableModel.addRow(row);
}
}
}
chunks - 要处理的中间结果process(java.util.List) protected void process(List<V> chunks)
publish 方法接收数据块。
有关详细信息,请参阅 publish(V...) 方法。
chunks - 要处理的中间结果publish(V...)protected void done()
doInBackground 方法完成后,在事件指派线程 上执行此方法。默认实现不执行任何操作。子类可以重写此方法,以在事件指派线程 上执行完成操作。注意,可以查询此方法实现内部的状态,以确定此任务的结果或者是否已经取消了此任务。
doInBackground(),
isCancelled(),
get()protected final void setProgress(int progress)
progress 绑定属性。该值应该在 0 到 100 之间。
由于在事件指派线程 上异步地通知 PropertyChangeListener,所以可以在调用任意 PropertyChangeListener 之前对 setProgress 方法进行多次调用。为了改进性能,所有这些调用都合并为一个只带最后一个调用参数的调用。
例如,以下调用:
setProgress(1); setProgress(2); setProgress(3);结果可能为带有值
3 的单个 PropertyChangeListener 通知。
progress - 要设置的进度值
IllegalArgumentException - 如果值不是从 0 到 100public final int getProgress()
progress 绑定属性。
public final void execute()
SwingWorker 以便在 worker 线程上执行。存在许多可用的 worker 线程。如果所有 worker 线程都忙于处理其他 SwingWorker,则此 SwingWorker 将被放入等待队列。
注:SwingWorker 被设计为只执行一次。多次执行 SwingWorker 将不会调用两次 doInBackground 方法。
public final boolean cancel(boolean mayInterruptIfRunning)
此方法返回后,对 Future.isDone() 的后续调用将始终返回 true。如果此方法返回 true,则对 Future.isCancelled() 的后续调用将始终返回 true。
Future<T> 中的 cancelmayInterruptIfRunning - 如果应该中断执行此任务的线程,则为 true;否则允许正在运行的任务运行完成
public final boolean isCancelled()
Future<T> 中的 isCancelledpublic final boolean isDone()
Future<T> 中的 isDone
public final T get()
throws InterruptedException,
ExecutionException
注:在此 SwingWorker 完成之前,在事件指派线程 上调用 get 将阻塞所有 事件(包括 repaint)的处理。
想在事件指派线程 上阻塞 SwingWorker 时,建议使用 模式对话框(modal dialog)。
例如:
class SwingWorkerCompletionWaiter extends PropertyChangeListener {
private JDialog dialog;
public SwingWorkerCompletionWaiter(JDialog dialog) {
this.dialog = dialog;
}
public void propertyChange(PropertyChangeEvent event) {
if ("state".equals(event.getPropertyName())
&& SwingWorker.StateValue.DONE == event.getNewValue()) {
dialog.setVisible(false);
dialog.dispose();
}
}
}
JDialog dialog = new JDialog(owner, true);
swingWorker.addPropertyChangeListener(
new SwingWorkerCompletionWaiter(dialog));
swingWorker.execute();
//the dialog will be visible until the SwingWorker is done
dialog.setVisible(true);
Future<T> 中的 getInterruptedException - 如果当前的线程在等待时被中断
ExecutionException - 如果计算抛出异常
public final T get(long timeout,
TimeUnit unit)
throws InterruptedException,
ExecutionException,
TimeoutException
有关更多信息,请参阅 get()。
Future<T> 中的 gettimeout - 等待的最大时间unit - timeout 参数的时间单位
InterruptedException - 如果当前的线程在等待时被中断
ExecutionException - 如果计算抛出异常
TimeoutException - 如果等待超时public final void addPropertyChangeListener(PropertyChangeListener listener)
PropertyChangeListener 添加到侦听器列表。该侦听器是为所有属性注册的。同一侦听器对象可以被添加多次,并且它们被调用的次数将与添加它们的次数相同。如果 listener 为 null,则不抛出任何异常并且不执行任何操作。
注:此方法只是一个便捷包装器。所有工作都委托给 getPropertyChangeSupport() 返回的 PropertyChangeSupport。
listener - 要添加的 PropertyChangeListenerpublic final void removePropertyChangeListener(PropertyChangeListener listener)
PropertyChangeListener。此方法移除一个为所有属性注册的 PropertyChangeListener。如果将 listener 多次添加到同一事件源,则在被移除之后,它获得的通知将减少一次。如果 listener 为 null,或者没有添加过,则不抛出任何异常并且不执行任何操作。
注:此方法只是一个便捷包装器。所有工作都委托给 getPropertyChangeSupport() 返回的 PropertyChangeSupport。
listener - 要移除的 PropertyChangeListener
public final void firePropertyChange(String propertyName,
Object oldValue,
Object newValue)
old 和 new 相等并且为非 null,则不触发任何事件。
此 SwingWorker 将成为所有已生成事件的源。
在事件指派线程 之外调用此方法时,则在事件指派线程 上异步地通知 PropertyChangeListener。
注:此方法只是一个便捷包装器。所有工作都委托给 getPropertyChangeSupport() 返回的 PropertyChangeSupport。
propertyName - 已更改属性的编程名称oldValue - 属性的旧值newValue - 属性的新值public final PropertyChangeSupport getPropertyChangeSupport()
SwingWorker 的 PropertyChangeSupport。当需要灵活地访问绑定属性支持时,使用此方法。
此 SwingWorker 将成为所有已生成事件的源。
注:如果在事件指派线程 之外调用 firePropertyChange 或 fireIndexedPropertyChange,则返回的 PropertyChangeSupport 在事件指派线程 上异步地通知所有 PropertyChangeListener。
SwingWorker 的 PropertyChangeSupportpublic final SwingWorker.StateValue getState()
SwingWorker 状态绑定属性。
|
JavaTM Platform Standard Ed. 6 |
|||||||||
| 上一个类 下一个类 | 框架 无框架 | |||||||||
| 摘要: 嵌套 | 字段 | 构造方法 | 方法 | 详细信息: 字段 | 构造方法 | 方法 | |||||||||
版权所有 2007 Sun Microsystems, Inc. 保留所有权利。 请遵守许可证条款。另请参阅文档重新分发政策。