JavaFX - Отмена задачи не работает

В приложении 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();
}
);

Почему задача не отменяется при нажатии кнопки?


person Joker 00    schedule 24.05.2017    source источник
comment
Вы должны обрабатывать отмену задачи внутри реализации. Пожалуйста, прочтите последний абзац перед примерами в документации: пользователь задачи запросит ее отмену, и автор задачи должен проверить, была ли она отменена в теле метода вызова.   -  person Itai    schedule 24.05.2017
comment
@sillyfly Да, это было полезно. Но как я могу проверить отмену задачи, если тяжелая часть выполняется в функции другого класса?   -  person Joker 00    schedule 24.05.2017
comment
Это во многом зависит от реализации этого другого класса. Универсального решения не существует, но обычно у вас либо есть задача, состоящая из множества более мелких шагов, поэтому вы можете проверять флаг на каждой итерации, либо у вас есть некоторая форма wait, которая будет реагировать на interrupt.   -  person Itai    schedule 24.05.2017
comment
Эта статья является весьма полезным (несмотря на то, что она устарела) объяснением прерывания потоков и может предоставить способ сделать то, что вам нужно.   -  person James_D    schedule 24.05.2017
comment
@sillyfly моя реализация на самом деле представляет собой метод файла JAR, который я вызываю и из которого получаю результаты. Есть ли способ отменить задание в этом случае?   -  person Joker 00    schedule 27.05.2017


Ответы (1)


Вы должны проверить состояние отмены (см. 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 создает циклическую зависимость. Однако вы можете использовать прокси или что-то другое, подходящее для вашей ситуации.
person beatngu13    schedule 24.05.2017
comment
Что, если тяжелую задачу выполняет функция из другого класса? И разве это не означает, что казнь никогда не закончится? - person Joker 00; 24.05.2017
comment
@Joker00 заставит этот класс знать о состоянии отмены. Например, введите объект Task в качестве параметра метода. Смотрите редактировать... - person beatngu13; 24.05.2017
comment
Это полезно, и я отмечаю ваш ответ как решающий, но у меня все еще есть одна проблема: тяжелая задача иногда выполняется функцией файла JAR, это просто вызывается и остается работать. Его код не виден и не редактируется, поэтому я не могу проверить отмену задачи так, как вы объяснили в своем ответе. Есть ли другой способ обойти это дело? - person Joker 00; 27.05.2017
comment
@ Joker00 Рад, что помог. Что касается вашего дополнительного вопроса: вы можете взглянуть на Как убить поток в Java? - person beatngu13; 28.05.2017