英文:
How to chain multiple SwingWorkers
问题
我有一个大型的后台任务,其中需要一些中间步骤来获取用户输入。
例如,buttonLoad_actionPerformed --> 加载,验证有效性 --> 如果过时,询问用户是否要更新。如果是 --> 更新,如果否 --> 停止。
目前,我已经像这样编写了这段代码:
// 加载任务
SwingWorker<Status,Object> swLoad = new SwingWorker<>() {
Validity doInBackground() {
return load(file);
}
void done() {
Validity validity = get();
switch (validity) {
case UPTODATE:
return;
case OUTDATED:
int res = JOptionPane.showConfirmDialog("文件已过时。您是否要更新它?");
if (res != JOptionPane.YES_OPTION)
return;
// 更新任务
SwingWorker<Boolean,Object> swUpdate = new SwingWorker<>() {
Boolean doInBackground() {
return update();
}
void done() {
Boolean success = get();
if (!success) ....
}
};
swUpdate.execute();
}
}
};
swLoad.execute();
然而,如果需要多个步骤,这可能会变得难以阅读。
如何最好地链接条件/可选的 SwingWorkers ?
英文:
I've got a big background task with some intermediate points where a user input is required.
E.g. buttonLoad_actionPerformed --> load, verify validity --> if outdated, ask user whether to update. If yes --> update, if no --> stop.
For now, I've coded this like this:
// load worker
SwingWorker<Status,Object> swLoad=new SwingWorker<> () {
Validity doInBackGround() {
return load(file);
}
void done() {
Validity validity=get();
switch (validity) {
case UPTODATE:
return;
case OUTDATED:
int res=JOptionPane.showConfirmDialog("File obsolete. Do you want to update it ?");
if (res != JOptionPane.YES_OPTION)
return;
// update worker
SwingWorker<Boolean,Object> swUpdate = new SwingWorker<>() {
Boolean doInBackGround() {
return update();
}
void done() {
Boolean success=get();
if (!success) ....
}
};
swUpdate.execute();
}
}
};
swLoad.execute();
However this can be become pretty unreadable if multiple steps are required.
What's the best approach for chaining conditional/optional SwingWorkers ?
答案1
得分: 2
我不明白为什么你在你的 done
方法中做任何事情。
Validity doInBackGround() {
Validity validity = load(file);
switch (validity) {
case UPTODATE:
return validity;
case OUTDATED:
int res= confirmOnEdt();
if (res == JOptionPane.YES_OPTION) {
Boolean success = update();
//检查更新并响应。
}
}
return validity;
}
public int confirmOnEDT() throws InterruptedException{
int[] container = {0};
SwingUtilities.invokeAndWait( () -> {
container[0] = JOptionPane.showConfirmDialog("文件已过时。您是否要更新它?");
}
);
return container[0];
}
一个 SwingWorker 用于全部任务。JOptionPane 会阻塞你的后台线程并等待输入。此外,你可能希望返回与 Validity
不同的返回值。
英文:
I don't understand why you're doing anything in your done
method.
Validity doInBackGround() {
Validity validity = load(file);
switch (validity) {
case UPTODATE:
return validity;
case OUTDATED:
int res= confirmOnEdt();
if (res == JOptionPane.YES_OPTION) {
Boolean success = update();
//check the update and respond.
}
}
return validity;
}
public int confirmOnEDT() throws InterruptedException{
int[] container = {0};
SwingUtilities.invokeAndWait( ()->{
container[0] = JOptionPane.showConfirmDialog("File obsolete. Do you want to update it ?");
}
);
return container[0];
}
One SwingWorker for the full set of tasks. The JOptionPane will block your background thread and wait for input. Also, you probably want to different return value than Validity
.
答案2
得分: 0
鉴于这是一个有点晦涩的问题,我会试着回答。
有2个问题引起了我的注意:
- 所示的函数/方法相当冗长。
- 嵌套的层次很深。
改进这些问题的一个简单解决方案是将代码拆分为单独的方法。例如,将“OUTDATED”情况中的可操作代码移到一个单独的方法中。虽然这会使代码变长,但更容易理解。
public loadInWorker() {
SwingWorker<Status,Object> swLoad = new SwingWorker<> () {
Validity doInBackground() {
return load(file);
}
void done() {
onLoad(get());
}
};
swLoad.execute();
}
private onLoad(Validity validity) {
switch (validity) {
case UPTODATE:
return;
case OUTDATED:
int res = JOptionPane.showConfirmDialog("文件已过时。您要更新吗?");
if (res == JOptionPane.YES_OPTION) {
updateInWorker();
}
}
}
private updateInWorker() {
SwingWorker<Boolean,Object> swUpdate = new SwingWorker<>() {
Boolean doInBackground() {
return update();
}
void done() {
Boolean success = get();
if (!success) {
onUpdateFailure();
}
}
};
swUpdate.execute();
}
private onUpdateFailure() {
// 这里是更新失败的代码
}
编辑 + 意见:
我要补充一下,我从未使用过这个worker API。看起来它似乎相当复杂。在我最后的Java开发日子里,我依赖于线程池来处理执行时间短的任务,并为执行时间长的任务使用专用线程。您还可以为SwingWorker调用编写一个包装器,因为您不关心它之外的内部类型。
以下是使用普通线程的示例:
public loadInThread() {
new Thread(this::loadInThread, "Load Thread").start();
}
private loadInThread() {
switch (load(file)) {
case UPTODATE:
return;
case OUTDATED:
int res = JOptionPane.showConfirmDialog("文件已过时。您要更新吗?");
if (res == JOptionPane.YES_OPTION) {
new Thread(this::updateInThread, "Update Thread").start();
}
}
}
private updateInThread() {
if (!update()) {
// 更新失败的代码放在这里
}
}
英文:
Given that this is a bit of an obscure question, I'll give it a shot.
There are 2 items that stand out for me:
- The shown function/method is rather lengthy
- There is a lot of nesting going on
A simple solution to improve those is to split out code into separate methods.
Example, move the actionable code from the "OUTDATED" case into a separate method. Sure it's longer, but easier to follow.
public loadInWorker() {
SwingWorker<Status,Object> swLoad=new SwingWorker<> () {
Validity doInBackGround() {
return load(file);
}
void done() {
onLoad(get());
}
}
};
swLoad.execute();
}
private onLoad(Validity validity) {
switch (validity) {
case UPTODATE:
return;
case OUTDATED:
int res=JOptionPane.showConfirmDialog("File obsolete. Do you want to update it ?");
if (res == JOptionPane.YES_OPTION) {
updateInWorker();
}
}
}
private updateInWorker() {
SwingWorker<Boolean,Object> swUpdate = new SwingWorker<>() {
Boolean doInBackGround() {
return update();
}
void done() {
Boolean success=get();
if (!success) {
onUpdateFailure();
}
}
};
swUpdate.execute();
}
private onUpdateFailure() {
....
}
Edit + Opinion:
I'll add that I've never used that worker API. Looking at it, it seems quite convoluted. In my last days of Java development, I relied on ThreadPools for tasks with a short execution time and dedicated Threads for tasks with long execution time.
You could also write a wrapper for the SwingWorker call as you don't care about the internal types outside of it.
Example using bog standard Threads:
public loadInThread() {
new Thread(this::loadInThread, "Load Thread").start();
}
private loadInThread() {
switch (load(file)) {
case UPTODATE:
return;
case OUTDATED:
int res=JOptionPane.showConfirmDialog("File obsolete. Do you want to update it ?");
if (res == JOptionPane.YES_OPTION) {
new Thread(this::updateInThread, "Update Thread").start();
}
}
}
private updateInThread() {
if (!update()) {
// Update Failure code goes here
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论