Concurrency JavaFX8中的任务链接:OnSucceed完成上一个任务后启动下一个任务
我是JavaFX8的新手,面临以下问题。在我当前用于文档处理/编辑的应用程序中,我有两个相当昂贵的任务。打开文档并保存文档 我的应用程序有“导入下一个”、“导出当前”和“导出当前和导入下一个”按钮。对于导入和导出,我有以下结构的两项任务:Concurrency JavaFX8中的任务链接:OnSucceed完成上一个任务后启动下一个任务,concurrency,javafx-8,Concurrency,Javafx 8,我是JavaFX8的新手,面临以下问题。在我当前用于文档处理/编辑的应用程序中,我有两个相当昂贵的任务。打开文档并保存文档 我的应用程序有“导入下一个”、“导出当前”和“导出当前和导入下一个”按钮。对于导入和导出,我有以下结构的两项任务: private class Export extends Task<Void> { public Export() { this.setOnRunning(event -> { // d
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;
}
}
私有类导出扩展任务{
公共出口(){
此.setOnRunning(事件->{
//做一些事情(改变光标等)
});
此.seton失败(事件->{
//做一些事情,例如显示错误框
});
此.setOnSucceed(事件->{
//做事
});
}
@凌驾
受保护的Void调用()引发异常{
//做昂贵的事
返回null;
}
}
我使用Executors.newSingleThreadExecutor()提交任务代码>
对于“导出当前和导入下一步”功能,我的目标是将导出和导入任务提交给执行器,但只有在导出任务成功并且setOnSucceedded
中给出的事件处理程序(在GUI线程上运行)完成时,我的导入任务才应该运行。如果导出失败,则加载下一个文档没有任何意义,因为需要用户交互。如何做到这一点
首先,我厌倦了在调用
方法中处理整个逻辑/错误,但这不起作用,因为我无法从该方法更改GUI(即显示错误框)
作为解决方法,我在导出任务中的
setOnSucceeded
的最后一行手动提交导入任务,但这不是很灵活,因为我希望确保此任务仅导出(不进行后续导入) 不要在任务
子类构造函数中调用处理程序属性方法setOnXXX
。这些方法实际上在任务上设置了一个属性,因此如果您也从其他地方调用这些方法,您将替换在类本身中实现的功能,而不是添加到类中
相反,请重写受保护的便利方法:
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 ;
}
}
这将把链接任务的逻辑放在您实际创建任务的位置,这似乎是正确的位置
请注意,为状态更改提供多个处理程序的另一种方法是使用stateProperty()
注册侦听器:
通过测试,这些不同机制的执行顺序似乎是:
处理程序
任务。成功
方法任务
子类中的代码,请执行以下操作
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() {
// ...
}
}
公共类导出扩展任务{
公共出口(){
stateProperty().addListener((obs、oldState、newState)->{
if(newState==Worker.State.RUNNING){
//做事
}else if(newState==Worker.State.successed){
//做事
}else if(newState==Worker.State.FAILED){
//做事
}
});
}
@凌驾
公开作废通知(){
// ...
}
}
最后,您可以在
调用
方法中实现整个逻辑:如果需要与UI交互,您可以将这些调用包装在平台.runLater(()->{})中代码>。但是,将功能划分为不同的任务可能会更干净。在您的示例中,“setOnSucceeded()”中的行是否会覆盖“Succeeded()”中之前给出的代码?或者按哪个顺序执行?它不会替换successed()
方法中的代码。通过快速测试,似乎首先执行处理程序setOnSucceeded()
。这两个任务都是在FX应用程序线程上执行的。好的,那么它并不能真正解决问题,因为下一个任务应该在任务定义中提供的代码(即,在successed()方法中)完成后提交
Export export = new Export();
export.stateProperty().addListener((obs, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
// ...
}
});
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() {
// ...
}
}