JavaFX - 取消任务不起作用。

3
在JavaFX应用程序中,我有一个方法,在大输入时需要很长时间。当它正在加载时,我会打开一个对话框,并希望用户能够取消/关闭对话框并退出任务。我创建了一个任务,并在取消按钮处理中添加了其取消。但是取消并没有发生,任务并没有停止执行。
Task<Void> task = new Task<Void>() {
    @Override
    public Void call() throws Exception {
        // calling a function that does heavy calculations in another class
    };
    task.setOnSucceeded(e -> {
        startButton.setDisable(false);
    });
}
new Thread(task).start();

cancelButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
    System.out.println("Button handled");
    task.cancel();
}
);

为什么点击按钮后任务没有被取消?

2
你必须在实现中处理取消任务的操作。请阅读文档中示例之前的最后一段:“Task 的使用者将请求取消它,而 Task 的作者必须在 call 方法体内检查它是否已被取消。” - Itai
@sillyfly 是的,那很有用。但是如果重要的部分在另一个类的函数中完成,我该如何检查任务的取消呢? - AbdelKh
1
这在很大程度上取决于另一个类的实现。并没有“万能解决方案”,但通常你要么有一个由许多较小“步骤”组成的任务,这样你就可以在每次迭代中检查一个标志,要么你有某种形式的wait,将响应一个interrupt - Itai
2
这篇文章虽然有些陈旧,但是对线程中断的解释非常有用,可能会为您提供所需的方法。 - James_D
@sillyfly 我的实现实际上是一个 JAR 文件方法,我调用它并从中获得结果。在这种情况下有没有办法取消任务? - AbdelKh
1个回答

4

您需要检查取消状态(请参阅 Task 的 Javadoc)。请查看此 MCVE

public class Example extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Task<Void> task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                new AnotherClass().doHeavyCalculations(this);
                return null;
            }
        };

        Button start = new Button("Start");
        start.setOnMouseClicked(event -> new Thread(task).start());

        Button cancel = new Button("Cancel");
        cancel.setOnMouseClicked(event -> task.cancel());

        primaryStage.setScene(new Scene(new HBox(start, cancel)));
        primaryStage.show();
    }

    private class AnotherClass {

        public void doHeavyCalculations(Task<Void> task) {
            while (true) {
                if (task.isCancelled()) {
                    System.out.println("Canceling...");
                    break;
                } else {
                    System.out.println("Working...");
                }
            }
        }

    }

}

请注意...
  • 您应该使用Task#updateMessage(String)而不是打印到System.out,这里仅供演示。
  • 直接注入Task对象会创建循环依赖。但是,您可以使用代理或适合您情况的其他内容。

如果重任务由另一个类中的函数完成,会怎样呢?而while true不意味着执行永远不会结束吗? - AbdelKh
1
@Joker00 让该类意识到取消状态。例如,将 Task 对象作为方法参数注入。请参见编辑... - beatngu13
这很有用,我将您的答案标记为解决方案,但我仍然有一个问题,重任务有时由JAR文件函数完成,只需调用并让其工作。它的代码不可见也不可编辑,因此,我无法按照您在答案中解释的方式检查任务的取消。在这种情况下还有其他方法吗? - AbdelKh
@Joker00 很高兴能帮到你。关于你的后续问题:你可能想看一下如何在Java中终止线程? - beatngu13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接