我希望用户等到我的方法调用下载一个文件(可能需要2到3分钟)完成。我为方法调用创建了一个新线程,并在内部调用它 run()
方法。根据返回值,应该显示一条消息,不管是成功还是错误。因此我不得不使用 join()
. 但这仍然冻结,因为ui仍在等待方法调用完成。我怎样才能克服这个问题(基本上,我需要使用一个线程使ui不冻结,同时,我希望根据方法的返回值显示一条消息)
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
processMsg.setText("Do not close. This may take few minutes...");
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
try {
ret = /*Method-call-which-takes-long-time*/
} catch (IOException ex) {
Logger.getLogger(JavaFXApplication1.class.getName()).log(Level.SEVERE, null, ex);
} catch (SQLException ex) {
Logger.getLogger(JavaFXApplication1.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
t1.start();
try {
t1.join();
} catch (InterruptedException ex) {
Logger.getLogger(JavaFXApplication1.class.getName()).log(Level.SEVERE, null, ex);
}
if (ret != null){
if (ret.equals("TRUE")){
pane.getChildren().remove(processMsg);
processMsg.setText("File downloaded at location: "+ chosenDir.getAbsolutePath());
pane.add(processMsg,0,11,2,1);
}
else{
pane.getChildren().remove(processMsg);
processMsg.setText(ret);
pane.add(processMsg,0,11,2,1);
}
}
}
});
3条答案
按热度按时间uxh89sit1#
您可能知道javafx呈现是由名为javafx application thread的线程处理的。您可以看到处于eclipse调试模式的线程。因此,如果使此线程等待另一个线程,则渲染将冻结。这就是这里发生的事情。
你可以做什么
单击此按钮时,禁用不希望用户单击的按钮。
使用容器轮询结果。这可以是一个全局队列,也可以使用rxjava优雅地实现
BehaviorSubject
或者其他合适的实现Subject
.当耗时的方法完成时,它将用结果或调用填充队列
onNext()
在rxjava上Subject
.当队列的侦听器或
Subject
获取值,然后重新启用按钮。让我看看能不能快速地把样品拼凑起来。同时,你可以自己试一试。
y1aodyip2#
根据返回值,应该显示一条消息,不管是成功还是错误。因此我不得不使用
join()
.这种假设是错误的。有几种方法可以从后台线程更新gui。
Platform.runLater
是最灵活的一种,但在这种情况下,我只建议使用Task
,它允许您通过onSucceeded
以及onFailed
属性时调用的属性call
逻辑完成时是否引发异常:bhmjp9jg3#
我建议您查看这个oracle教程,了解如何在ui组件之外处理业务逻辑。
另外,对于您的问题,使用completablefuture将对执行此类异步工作有很大帮助。
具体来说,
whenComplete()
如果你在一个CompletableFuture
然后再显示消息。以下是whencomplete()的参考