我对JavaFX8很新,面临以下问题。在我目前用于文档处理/编辑的应用程序中,我有两个相当昂贵的任务。打开文档并保存文档。
我的应用程序有按钮"导入下一个","导出当前"和"导出当前并导入下一个"。对于导入和导出,我有两个以下结构的任务:
private class Export extends Task<Void> {
public Export() {
this.setOnRunning(event -> {
// do stuff (change cursor etc)
});
this.setOnFailed(event -> {
// do stuff, eg. show error box
});
this.setOnSucceeded(event -> {
// do stuff
});
}
@Override
protected Void call() throws Exception {
// do expensive stuff
return null;
}
}
我使用Executors.newSingleThreadExecutor();
提交任务。
对于功能&#34;导出当前和导入下一个&#34;,我的目标是将导出和导入任务提交给执行程序,但我的导入任务只应在导出任务成功和EventHandler时运行在setOnSucceedded
中给出(在GUI线程上运行)已完成。如果导出失败,则加载下一个文档没有任何意义,因为需要用户交互。如何实现这一目标?
首先,我对call
方法中的整个逻辑/错误处理感到厌倦,但这不起作用,因为我无法从此方法更改GUI(即显示错误框)。
作为解决方法,我在导出任务的setOnSucceeded
的最后一行手动提交导入任务,但这不是很灵活,因为我想确保此任务导出只(没有后续导入)......
答案 0 :(得分:3)
不要在setOnXXX
子类构造函数中调用处理程序属性方法Task
。这些实际上在任务上设置了一个属性,所以如果你也从其他地方调用这些方法,你将替换你在类本身中实现的功能,而不是添加它。
相反,覆盖受保护的便利方法:
public class Export extends Task<Void> {
@Override
protected void succeeded() {
super.succeeded();
// do stuff...
}
@Override
protected void running() {
super.running();
// do stuff...
}
@Override
protected void failed() {
super.failed();
// do stuff...
}
@Override
protected Void call() {
// do expensive stuff....
return null ;
}
}
现在,您可以安全地在setOnXXX(...)
类外部使用Export
,而不会破坏其功能:
Export export = new Export();
export.setOnSucceeded(e -> {
Import import = new Import();
executor.submit(import);
});
executor.submit(export);
这就是将任务链接到你实际创建它们的逻辑,这似乎是正确的地方。
请注意,为状态更改提供多个处理程序的另一种方法是使用stateProperty()
注册侦听器:
Export export = new Export();
export.stateProperty().addListener((obs, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
// ...
}
});
从测试开始,这些不同机制的执行顺序似乎是:
onSucceeded
处理程序Task.succeeded
方法所有都在FX申请主题上执行。
因此,如果您希望在外部添加处理程序之前执行<{1}}子类中的代码,请执行
Task
最后,您可以在public class Export extends Task<Void> {
public Export() {
stateProperty().addListener((obs, oldState, newState) -> {
if (newState == Worker.State.RUNNING) {
// do stuff
} else if (newState == Worker.State.SUCCEEDED) {
// do stuff
} else if (newState == Worker.State.FAILED) {
// do stuff
}
});
}
@Override
public Void call() {
// ...
}
}
方法中实现整个逻辑:如果您需要与UI进行交互,则可以将这些调用包装在call
中。但是,无论如何,将功能分离到不同的任务可能更加清晰。