0

我有一个实现 StreamResourceWriter 接口的 FileCreator 类和一个实现 ErrorHandler 的 MainErrorHandler 类。我MainErrorHandler在我的项目中使用该类作为集中的异常处理程序,它主要记录异常并向用户显示通知。问题是 StreamResourceWriter.accept() 方法在非 UI 线程中运行,当抛出异常时,它被定向到 ErrorHandler,然后由于“ IllegalStateException:UI 实例不可用”而无法显示通知。当 FileCreator 在方法中抛出错误时,有没有办法从 MainErrorHandler 向用户显示通知窗口accept()

在 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 并直接调用它。

4

1 回答 1

0

有办法,但并不完美。

您可以通过VaadinSession.getCurrent().getUIs().

要过滤掉非活动/分离的 UI,您可以检查是否ui.getSession()返回 a VaadinSession(所以,不是 null)。JavaDocgetSession说:

如果 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(例如多个选项卡)。

于 2019-03-22T13:46:59.903 回答