Результат вызова Screens.getOpenedScreens().getRootScreenOrNull() всегда = null после повторного логина пользователя

Здравствуйте!

Возникла задача логировать открытие экранов приложения пользователями, причем сохранять не только текущий открытый, а также предыдущий экран. Получить текущий открытый экран удалось через реализацию ApplicationListener (т.к. в методе Screens.show происходит publish события ScreenOpenedEvent). Далее возник вопрос, как получить предыдущий экран, это, судя по всему, можно сделать через интерфейс Screens и анализ currentBreadcrumbs, примерно таким образом:

Collection<Screen> breadCrumbs = screens.getOpenedScreens().getCurrentBreadcrumbs();
if (breadCrumbs.size() == 0)
    //предыдущего экрана нет - только залогинились
    return null;
else if (breadCrumbs.size() == 1)
    //предыдущий экран - root-экран
    return screens.getOpenedScreens().getRootScreen();
else
    //предыдущий экран - последний из breadCrumbs
    return breadCrumbs.stream().skip(breadCrumbs.size() - 1).findFirst().orElse(null);

Всё работает до того момента, пока пользователь не выйдет из приложения и не попробует залогиниться еще раз. После этого на вызове screens.getOpenedScreens().getCurrentBreadcrumbs() вылетает исключение IllegalStateException(“There is no root screen opened”). Внутри метода getCurrentBreadcrumbs() происходит попытка получения root screen (ui.getTopLevelWindow()), и почему-то topLevelWindow == null. Получается, при первом логине приложение видит topLevelWindow и его можно получить (а соответственно, и breadcrumbs, и вычислить предыдущий экран), а при повторном логине topLevelWindow почему-то равен null (и вычислить предыдущий экран через breadcrumbs уже нельзя).

Прикладываю пример проекта, где всё это можно воспроизвести (версия Jmix: 1.0.3, новый пустой проект, созданный через studio, вся логика получения экранов сосредоточена в com.company.test.app.ScreenOpenListener).

Как можно обойти эту проблему? Может быть возможно получить предыдущий открытый пользователем экран другим способом?

test.zip (76.4 КБ)

Добрый день.

В классе ScreenOpenListener Вы самостоятельно инициализируете Screens, что делать нельзя, т.к. этот бин имеет @Scope("vaadin-ui"). Другими словами он привязан к текущему 'экземпляру AppUI, т.е. вкладке браузера. Правильный способ получения Screens:

@Nullable
private Screens getScreens() {
    AppUI appUI = AppUI.getCurrent();
    return appUI != null ? appUI.getScreens() : null;
}

Глеб

1 симпатия

Спасибо, проблема решена