在单独的线程上提示用户

时间:2015-09-22 01:41:07

标签: java javafx

我正在编写一个可以更新自己的程序。我创建了一个单独的线程来检查服务器的更新(因为不阻止UI更新)。一旦更新完成检查,并确定有更新版本可用,它应该询问用户是否希望获得这些更新。

这是我的shouldApplyUpdates方法:

public boolean shouldApplyUpdate() {
    Alert updateAlert = new Alert(Alert.AlertType.CONFIRMATION);
    updateAlert.setTitle(resourceBundle.getString("ui.gui.update.title"));
    updateAlert.setContentText(resourceBundle.getString("ui.gui.update.message"));
    Optional<ButtonType> ret = updateAlert.showAndWait();
    return ret.get() == ButtonType.OK;
}

它应该做的是提示用户是否要应用更新,如果是,则返回true。问题是,因为这个方法是从另一个线程调用的,所以抛出异常就不会出现在JavaFX应用程序线程上(在我的情况下,无声地,所以我不得不用try / catch包围方法来查看异常)。

这是我的更新主题:

new Thread(new Task<Void>() {
    @Override
    protected Void call() throws Exception {
        //Check for updates
        ...
        //If updates are available, call shouldApplyUpdates()
        if(shouldApplyUpdates()){
            //Apply the updates
        }
        return null;
    }
}).start();
//Create GUI and stuffs, all should be happening while updates are being checked

所以我需要的是创建并在Application Thread上显示对话框,然后阻止该方法返回(由于单独的线程,该方法是安全的被阻止)。然后在用户确认他的选择后,返回方法。

实现这一目标的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

我不确定您是否需要阻止该方法返回。你可以这样做:

Task<Boolean> checkForUpdateTask = new Task<Boolean>() {
    @Override
    public Boolean call() throws Exception {
        // check for updates...
        if (/* updates available */) {
            return true ;
        } else {
            return false ;
        }
    }
};
checkForUpdateTask.setOnSucceeded(e -> {
    if (checkForUpdateTask.getValue() && shouldApplyUpdates()) {
        // apply updates...
    } else {
        // proceed....
    }
});
checkForUpdateTask.setOnFailed(e -> {
    checkForUpdateTask.getException().printStackTrace();
});
new Thread(checkForUpdateTask).start();

如果确实需要阻止该方法返回,可以使用以下习语。这是基于JavaFX2: Can I pause a background Task / Service?

的解决方案
Task<Void> checkForUpdateTask = new Task<Void>() {
    @Override
    public Void call() throws Exception {
        // check for updates...
        if (/* updates available */) {
            FutureTask<Boolean> checkUser = new FutureTask<Boolean>(() -> shouldApplyUpdates());
            Platform.runLater(checkUser);

            // checkUser.get() will block until it returns a value...
            if (checkUser.get()) {
                // apply updates...
            }
        }
        return null ;
    }
};
new Thread(checkForUpdateTask).start();

在这个版本中,// apply updates...代码块在后台线程上执行,这可能就是你想要的。