1 回答

TA貢獻1860條經驗 獲得超8個贊
您絕不能在JavaFX 應用程序線程上運行長時間運行的任務。這樣做將阻止所述線程執行任何導致 UI 凍結的與 GUI 相關的事情。這讓您的用戶感到難過。但是,您嘗試將長時間運行的任務放在后臺任務上是有缺陷的。您調用Thread.joinwhich 將阻塞調用線程,直到目標線程死亡;這實際上與在調用線程上運行任務相同。
為了快速修復您的示例,您可以執行以下操作:
@FXML
private void test(){
textField.setText("Pending...");
Thread t = new Thread(){
@Override public void run(){
boolean passed = doStuff();
Platform.runLater(() -> {
if(passed){
textField.setText("OK");
} else {
textField.setText("Error");
}
});
}
};
t.start();
}
這將創建一個線程,啟動它,讓它在后臺運行,同時讓JavaFX 應用程序線程繼續做它需要做的事情。在后臺線程內部,您必須更新TextField內部Platform.runLater(Runnable)調用。這是必需的,因為您絕不能從 JavaFX 應用程序線程以外的線程更新實時場景圖;這樣做會導致未定義的行為。此外,您應該查看Java 中的“實現可運行”與“擴展線程”。這樣做更好,或者至少更慣用:
Thread t = new Thread(() -> { /* background code */ });
您還可以使用 a javafx.concurrent.Task,它可以更輕松地與JavaFX Application Thread進行通信。一種選擇是:
@FXML
private void test(){
textField.setText("Pending...");
Task<Boolean> task = new Task<>() {
@Override protected Boolean call() throws Exception {
return doStuff();
}
};
task.setOnSucceeded(event -> textField.setText(task.getValue() ? "Ok" : "Error"));
new Thread(task).start();
}
您還可以將 綁定TextField到方法的message屬性并在方法內Task調用。如果可能,您甚至可以提供更詳細的消息。updateMessage("Pending...")call
也就是說,Thread自己創建和啟動 s 并不理想,您應該研究線程池(使用類似 an 的東西ExecutorService)。您可能還想研究javafx.concurrent.Service“重用” Tasks。
有關 JavaFX 并發的更多信息,請參閱 JavaFX中的并發并閱讀javafx.concurrent. 有關 Java 中多線程的基礎知識,請參閱課程: Java? 教程中的并發。
添加回答
舉報