API调用似乎阻止了JavaFX代码



嘿,我从JavaFX视图提交时遇到了问题。在提交我想实现以下链:

  1. 将光标更改为等待符号
  2. 设置标签文本"正在加载…"
  3. 进行API调用
  4. 将标签文本设置为"已完成,请点击刷新"
  5. 将光标设置回默认值

我想这样做,因为API调用确实锁定了(web)视图的其余部分,我不希望用户点击并导致程序崩溃。我写了这个代码来实现我上面描述的事件链

Button submit = new Button();
submit.setPadding(new Insets(5));
submit.setText("Submit");
submit.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event) {
        try {
            scene.setCursor(Cursor.WAIT);
            label.setText("loading...");
            System.out.println("loading");
            model.newRootNode(searchIndividual.getText(), Integer.valueOf(numberField.getText()));
            // This makes the API call
            System.out.println("finished");
            label.setText("Done! Please hit 'Refresh'");
            scene.setCursor(Cursor.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});
vbox.getChildren().add(submit);

使用eclipse调试器,我无法使标签文本更改可见,但光标似乎可以工作。此外,我使用sysouts()来检查API调用前后的代码是否得到执行,并打印loadingfinished。标签被设置为Done! Please hit 'Refresh',如果我以后不重写它的话,它会将光标设置为cursor.WAIT
为什么API调用之前的代码似乎没有执行?或者说给出视觉反馈?

从ui线程调用事件处理程序,在更改ui内容后,该线程无法自由刷新场景。在另一个线程上执行长时间运行的操作,并让ui线程继续执行它的工作来修复此问题。您可以简单地使用Platform.runLater从您启动的非ui线程对ui进行更改,或者使用Task,它的设计目的是完成这样的工作:

Task<Void> task = new Task<Void>() {
    @Override
    protected Void call() throws Exception {
        // makes the long-running API call
        return null;
    }
};
task.setOnRunning((WorkerStateEvent event) -> {
    // disable ui
});
task.setOnCancelled((WorkerStateEvent event) -> {
    // reenable ui
    // handle cancel
});
task.setOnSucceeded((WorkerStateEvent event) -> {
    // reenable ui
    // handle succeed
});
task.setOnFailed((WorkerStateEvent event) -> {
    // reenable ui
    // handle failed task e.g.:
    System.err.println("Oops, Error:");
    task.getException().printStackTrace(System.err);
});
Thread t = new Thread(task);
// thread shouldn't prevent program shutdown
t.setDaemon(true);
t.start();

还要注意,在处理异常的方式中,如果抛出异常,ui将不会再次解锁,因为代码的这一部分位于发生异常的块内。