JavaFX桌面應用未響應問題解決方案
日常使用軟件的過程中,偶爾會遇到軟件突然卡住,再點擊幾次就變成“未響應”的情況。
在JavaFX應用中同樣也會出現這種情況,在開發(fā)過程中應該盡量避免這種情況的出現。
1. “未響應”重現
應用程序出現“未響應”這種情況往往是因為在UI線程中處理一些耗時的業(yè)務,當UI線程在處理耗時的業(yè)務時,UI就會卡住。
下面通過一個示例(獲取Google頁面title信息)來演示一下“未響應”這種情況。
這里使用 jsoup 來抓取Google頁面的title信息,需要引入jsoup的maven依賴:
<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.13.1</version> </dependency>
編譯AppService,實現抓取Google頁面的title信息。
public class AppService {
public static final AppService INSTANCE = new AppService();
private AppService() {
}
public String visitGoogle() {
try {
Document document = Jsoup.parse(new URL("https://www.google.com"), 10_000);
return document.head().getElementsByTag("title").get(0).text();
} catch (Exception e) {
return e.getMessage();
}
}
}
因為沒有F墻,這里訪問Google肯定是超時的,這里設置了超時10秒。
接著改造AppUI,當點擊Go按鈕的時候,調用visitGoogle并將結果顯示在界面上。
public class AppUI implements Initializable {
public Label text;
private AppService appService = AppService.INSTANCE;
private AppModel model = new AppModel();
@Override
public void initialize(URL location, ResourceBundle resources) {
text.textProperty().bindBidirectional(model.textProperty());
model.setText("Hello JavaFX.");
}
public void click(ActionEvent event) {
model.setText(appService.visitGoogle());
}
}
運行JavaFX應用,當點擊第一個Go按鈕之后,再點擊其他按鈕界面就會卡住,出現“未響應”的現象。

2. UI線程、業(yè)務線程分離
前面有提到,出現“未響應”這種情況是因為在UI線程中處理一些耗時的業(yè)務,當UI線程在處理耗時的業(yè)務時,UI就會卡住。
所以如果能將UI線程和業(yè)務線程分開來,這樣就能解決界面卡住的問題了。
改造一下AppUI,將調用visitGoogle的代碼放到新線程去執(zhí)行。
public void click(ActionEvent event) {
new Thread(() -> model.setText(appService.visitGoogle())).start();
}
這里直接采用new的方式創(chuàng)建線程,實際應用中最好是使用線程池。
雖然將業(yè)務代碼放在新線程中處理解決了界面卡住的問題,但是上面的代碼中,通過model.setText()來改變標簽(Label)的文字。
實際上會發(fā)現程序運行后會出現異常,一旦我們在非UI線程中嘗試改變UI效果,程序就會拋出下面的異常。

界面卡住的問題雖然解決了,但又出現了新的問題。
3. 在UI線程更新UI
在UI線程處理業(yè)務會導致界面卡住,在業(yè)務線程更新UI會出現異常,為了能在業(yè)務線程中更新UI,JavaFX為開發(fā)者提供了一個Platform類。
只需要在業(yè)務線程中,將更新UI的代碼放在這個類的runLater方法中執(zhí)行即可。
下面再次改造AppUI
public void click(ActionEvent event) {
new Thread(() -> {
String title = appService.visitGoogle();
Platform.runLater(() -> model.setText(title));
}).start();
}
這里還是將業(yè)務代碼放在新線程中執(zhí)行,但是涉及UI更新的代碼model.setText()則放在Platform.runLater()里面執(zhí)行。
這樣,就解決了界面卡住以及非UI線程更新UI出現異常的問題了。

通過改造,雖然請求Google超時了,但是UI并沒有卡住,同時界面也得到了更新。
所以特別注意,在開發(fā)過程中應該盡量避免:
在UI線程中處理業(yè)務在業(yè)務線程中更新UI
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Spring MVC學習教程之RequestMappingHandlerMapping匹配
這篇文章主要給大家介紹了關于Spring MVC學習教程之RequestMappingHandlerMapping匹配的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧2018-11-11
Intellij Idea修改代碼方法參數自動提示快捷鍵的操作
這篇文章主要介紹了Intellij Idea修改代碼方法參數自動提示快捷鍵的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01
深入了解Maven Settings.xml文件的結構和功能
這篇文章主要為大家介紹了Maven Settings.xml文件基本結構和功能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11
Springboot初始化啟動報錯Error?creating?bean?with?name?'da
這篇文章主要為大家介紹了Springboot初始化啟動報Error?creating?bean?with?name?'dataSource'?defined?in?class?path?resource解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08

