有什么不同吗? SwingWorker#publish 与 SwingUtilities#invokeLater
Is there any difference? SwingWorker#publish vs SwingUtilities#invokeLater
假设我们有一个 long/heavy 任务必须 运行 在后台运行,并将其进度或其他任何内容发布到 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();
}
在这两种情况下,label.setText()
是对 GUI 的更新,运行 是对事件调度线程的更新。它们有什么不同?
当然,问题还在于,为什么我应该对 worker 实施 done()
方法,而不是在 doInBackground
方法末尾调用 SwingUtilities.invokeLater
?除了处理 doInBackground
方法中可能抛出的异常。
在 class 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
关于classSwingWorker
中的方法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
] 任务完成后我需要执行的任务。但是of-course, YMMV.
假设我们有一个 long/heavy 任务必须 运行 在后台运行,并将其进度或其他任何内容发布到 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();
}
在这两种情况下,label.setText()
是对 GUI 的更新,运行 是对事件调度线程的更新。它们有什么不同?
当然,问题还在于,为什么我应该对 worker 实施 done()
方法,而不是在 doInBackground
方法末尾调用 SwingUtilities.invokeLater
?除了处理 doInBackground
方法中可能抛出的异常。
在 class 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
关于classSwingWorker
中的方法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
] 任务完成后我需要执行的任务。但是of-course, YMMV.