我有一个实现StreamResourceWriter接口的FileCreator类和一个实现ErrorHandler的MainErrorHandler类。我在项目中使用MainErrorHandler
类作为集中式异常处理程序,该处理程序主要记录异常并向用户显示通知。问题在于StreamResourceWriter.accept()方法在非UI线程中运行,并且在引发Exception时将其定向到ErrorHandler,该错误处理由于“ IllegalStateException ”而无法显示通知:UI实例为无法使用”。 当FileCreator在accept()
方法中引发错误时,是否可以通过MainErrorHandler向用户显示通知窗口?
在FileCreator片段下方。
public class FileCreator implements StreamResourceWriter {
@Override
public void accept(OutputStream stream, VaadinSession session) throws IOException {
// Run in a non ui thread.
// Writes to OutputStream but an Exception might be thrown during this process
}
}
MainErrorHandler代码段下方。
/**
* Centralized error handler
*/
public class MainErrorHandler implements ErrorHandler {
private static final Logger log = LoggerFactory.getLogger(MainErrorHandler.class);
@Override
public void error(ErrorEvent event) {
log.error("Error occurred", event.getThrowable());
//Cannot show a notification if ErrorEvent came from FileCreator.
//Will get an IllegalStateException: UI instance is not available.
Notification.show("Error occurred");
//Tried UI.getCurrent but it returns null if ErrorEvent came from FileCreator.
UI.getCurrent();
}
}
使用Vaadin 13.0.1。
编辑
解决此问题的一种方法是将UI引用直接传递给FileCreator。下面是一个例子。
public class FileCreator implements StreamResourceWriter {
private UI ui;
//Pass UI reference directly
public FileCreator(UI ui){
this.ui = ui;
}
@Override
public void accept(OutputStream stream, VaadinSession session) throws IOException {
try{
// Run in a non ui thread.
// Writes to OutputStream but an Exception might be thrown during this process
}catch(Exception e){
//I don't like this since have to catch all exceptions and have to call ErrorHandeler directly with a UI reference. Also what if somewhere in code ErrorHandler is changed and is not of type MainErrorHandler.
((MainErrorHandler)VaadinSession.getCurrent().getErrorHandler()).error(e, ui);
}
}
}
正如我在评论中所说,我真的也不喜欢这种方法,因为我被迫捕获所有异常,必须将ErrorHandler强制转换为MainErrorHandler并直接调用它。
答案 0 :(得分:0)
有办法,但并不完美。
您可以通过VaadinSession.getCurrent().getUIs()
获取所有UI实例。
要过滤掉无效/分离的UI,您可以检查ui.getSession()
是否返回VaadinSession
(因此,不为null)。 getSession
的JavaDoc说:
如果UI当前未附加到VaadinSession,则该方法将返回null。
然后,您可以在每个UI上调用access
方法,并在UI上下文中创建并显示通知。
for(UI ui : VaadinSession.getCurrent().getUIs()) {
// Filtering out detached/inactive UIs
if (ui.getSession() != null) {
ui.access(() -> {
// create Notification here
});
}
我说这并不完美,因为您必须牢记用户可以同时打开多个UI(例如,多个选项卡)。