Han*_*nes 15 java exception-handling javafx java-8 javafx-8
给定一个场景的控制器调用业务代码引发异常.我怎样才能以一般方式处理这类例外?
我尝试了这个Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler)
方法,但是没有调用它,所以我相信异常会在JavaFX框架内的某个地方被捕获.
我该怎么做才能处理此异常或至少向用户显示一些有用的信息?
Jam*_*s_D 28
从JavaFX 8开始,Thread.setDefaultUncaughtExceptionHandler(...)
应该可以工作:参见RT-15332.
如果在执行start(...)
方法期间发生未捕获的异常,则事情会有点复杂.根据应用程序的启动方式,调用的代码start()
(例如,实现Application.launch(...)
)可能会捕获异常并处理它,这显然会阻止调用默认的异常处理程序.
特别是,在我的系统(Mac OS X 10.9.5上的JDK 1.8.0_20)上,如果我的应用程序通过main(...)
调用的方法启动Application.launch(...)
,start()
则会捕获该方法中抛出的任何异常(而不是重新抛出).
但是,如果我删除main(...)
方法(请参阅下面的注释)并直接启动应用程序,start()
则会重新抛出方法中抛出的任何异常,从而允许调用默认的异常处理程序.请注意,它不仅仅是向上传播.start()
在FX应用程序线程上调用,并从主线程重新抛出异常.实际上,当发生这种情况时,假定FX应用程序线程正在运行的默认处理程序中的代码无法运行:所以我的猜测是在这种情况下启动代码捕获start()
方法中的异常,并在catch
块中关闭FX Application Thread
,和然后从调用线程重新抛出异常.
所有这一切的结果是它很重要 - 如果您希望默认处理程序处理start()
方法中的异常,如果FX应用程序线程上没有抛出异常(即使是通过a Platform.runLater(...)
),则不应调用任何UI代码.
注意:(对于那些可能不知道这一点的人).从Java 8开始,Application
即使没有main(...)
方法,也可以通过以通常的方式将类名作为参数传递给JVM可执行文件来直接启动子类(即java MyApp
).这可以满足您的期望:启动FX工具包,启动FX Application线程,实例化子Application
类和调用init()
,然后启动FX Application Thread调用start()
.有趣的是(并且可能是错误的),对于main(...)
方法中Application.launch()
未捕获的异常,调用的方法行为略有不同start(...)
.
这是一个基本的例子.取消注释代码Controller.initialize()
以查看start()
方法中抛出的异常.
package application;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Thread.setDefaultUncaughtExceptionHandler(Main::showError);
Parent root = FXMLLoader.load(getClass().getResource("Main.fxml"));
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
}
private static void showError(Thread t, Throwable e) {
System.err.println("***Default exception handler***");
if (Platform.isFxApplicationThread()) {
showErrorDialog(e);
} else {
System.err.println("An unexpected error occurred in "+t);
}
}
private static void showErrorDialog(Throwable e) {
StringWriter errorMsg = new StringWriter();
e.printStackTrace(new PrintWriter(errorMsg));
Stage dialog = new Stage();
dialog.initModality(Modality.APPLICATION_MODAL);
FXMLLoader loader = new FXMLLoader(Main.class.getResource("Error.fxml"));
try {
Parent root = loader.load();
((ErrorController)loader.getController()).setErrorText(errorMsg.toString());
dialog.setScene(new Scene(root, 250, 400));
dialog.show();
} catch (IOException exc) {
exc.printStackTrace();
}
}
// public static void main(String[] args) {
// launch(args);
// }
}
Run Code Online (Sandbox Code Playgroud)
使用Main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.geometry.Insets?>
<HBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller"
alignment="center" spacing="5">
<children>
<Button text="Do something safe" onAction="#safeHandler" />
<Button text="Do something risky" onAction="#riskyHandler" />
<Label fx:id="label" />
</children>
<padding>
<Insets top="10" left="10" right="10" bottom="10" />
</padding>
</HBox>
Run Code Online (Sandbox Code Playgroud)
Controller.java:
package application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class Controller {
private final IntegerProperty counter = new SimpleIntegerProperty(1);
@FXML
private Label label ;
public void initialize() throws Exception {
label.textProperty().bind(Bindings.format("Count: %s", counter));
// uncomment the next line to demo exceptions in the start() method:
// throw new Exception("Initializer exception");
}
@FXML
private void safeHandler() {
counter.set(counter.get()+1);
}
@FXML
private void riskyHandler() throws Exception {
if (Math.random() < 0.5) {
throw new RuntimeException("An unknown error occurred");
}
safeHandler();
}
}
Run Code Online (Sandbox Code Playgroud)
Error.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.ErrorController">
<center>
<ScrollPane>
<content>
<Label fx:id="errorMessage" wrapText="true" />
</content>
</ScrollPane>
</center>
<bottom>
<HBox alignment="CENTER">
<Button text="OK" onAction="#close"/>
</HBox>
</bottom>
</BorderPane>
Run Code Online (Sandbox Code Playgroud)
ErrorController.java:
package application;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class ErrorController {
@FXML
private Label errorMessage ;
public void setErrorText(String text) {
errorMessage.setText(text);
}
@FXML
private void close() {
errorMessage.getScene().getWindow().hide();
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
14300 次 |
最近记录: |