Java FX 防止 UI 冻结

Rav*_*kar -1 java multithreading javafx

我希望用户等待我的方法调用下载文件(这可能需要大约 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);
         }
      }
   }
});
Run Code Online (Sandbox Code Playgroud)

fab*_*ian 5

根据返回值,应该显示一条消息,无论是成功还是错误。因此我不得不使用join().

这个假设是错误的。有多种方法可以从后台线程更新 GUI。Platform.runLater是最灵活的一个,但在这种情况下,我只推荐使用Task,它允许您通过onSucceededonFailed属性添加处理程序 ,这些属性在call逻辑完成时调用或不抛出异常:

Task<MyReturnType> task = new Task<MyReturnType>() {

    @Override
    protected MyReturnType call() throws Exception {
        return someLongCalculation(); // may throw an exception
    }

};

task.setOnSucceeded(evt -> {
    // we're on the JavaFX application thread here
    MyReturnType result = task.getValue();
    label.setText(result.toString());

});

task.setOnFailed(evt -> {
    // we're on the JavaFX application thread here
    label.setText("Error: " + task.getException().getMessage());
});
new Thread(task).start(); // alternatively use ExecutorService
Run Code Online (Sandbox Code Playgroud)

Task.updateValue,Task.updateMessageTask.updateProgress允许您将可以使用value,messageprogress属性观察到的部分结果传达回来;这些属性在 JavaFX 应用程序线程上更新。