JavaFX8中的任务链接:在onSucceeded完成上一个任务

时间:2016-01-16 10:50:08

标签: concurrency javafx-8

我对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的最后一行手动提交导入任务,但这不是很灵活,因为我想确保此任务导出只(没有后续导入)......

1 个答案:

答案 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) {
        // ...
    }
});

从测试开始,这些不同机制的执行顺序似乎是:

  1. 州听众
  2. onSucceeded处理程序
  3. Task.succeeded方法
  4. 所有都在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中。但是,无论如何,将功能分离到不同的任务可能更加清晰。