Как проверить, имеет ли текущая активность диалоговое окно впереди?

Я использую стороннюю библиотеку, и иногда появляется диалог. Прежде чем завершить текущую работу, я хочу проверить, появилось ли диалоговое окно в текущем контексте.

Есть ли API для этого?

Ответ 1

Вы можете проверить, работает ли он над активными фрагментами этого действия и проверяет, является ли один из них DialogFragment, что означает, что на экране есть активное диалоговое окно:

    public static boolean hasOpenedDialogs(FragmentActivity activity) {
        List<Fragment> fragments = activity.getSupportFragmentManager().getFragments();
        if (fragments != null) {
            for (Fragment fragment : fragments) {
                if (fragment instanceof DialogFragment) {
                    return true;
                }
            }
        }

        return false;
    }

Ответ 2

Я столкнулся с аналогичной проблемой и не хотел изменять все местоположения, где создавались и показывались диалоги. Мое решение состояло в том, чтобы посмотреть, был ли просмотр, который я показывал, с помощью hasWindowFocus(). Это не будет работать во всех ситуациях, но работает в моем конкретном случае (это было для внутреннего приложения записи, используемого в довольно ограниченных обстоятельствах).

Это решение не было тщательно проверено на надежность, но я решил, что я опубликую его, если он поможет кому-то.

Ответ 3

AFAIK - для этого нет публичного API.

Рекомендуемый способ состоит в том, чтобы иметь ссылку на диалог и проверять isShowing() и при необходимости dismiss(), но поскольку вы используете стороннюю библиотеку, это могут быть не варианты для вас.

Лучше всего проверить документацию для библиотеки, которую вы используете. Если это не поможет, вам не повезло.

Подсказка: активность переключается в состояние "приостановлено", если появляется диалоговое окно. Вы можете "злоупотреблять" этим поведением;)

Ответ 4

Это использует отражения и скрытые API для получения активных корней. Если появится диалоговое окно с предупреждением, это приведет к возврату дополнительного корня представления. Но осторожно, так как даже всплывающее окно с тостами вернет дополнительный корень представления.

Я подтвердил совместимость с Android 4.1 до Android 6.0, но, конечно, это может не работать в более ранних версиях Android.

Я не проверял поведение для многооконных режимов.

@SuppressWarnings("unchecked")
public static List<ViewParent> getViewRoots() {

    List<ViewParent> viewRoots = new ArrayList<>();

    try {
        Object windowManager;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            windowManager = Class.forName("android.view.WindowManagerGlobal")
                    .getMethod("getInstance").invoke(null);
        } else {
            Field f = Class.forName("android.view.WindowManagerImpl")
                    .getDeclaredField("sWindowManager");
            f.setAccessible(true);
            windowManager = f.get(null);
        }

        Field rootsField = windowManager.getClass().getDeclaredField("mRoots");
        rootsField.setAccessible(true);

        Field stoppedField = Class.forName("android.view.ViewRootImpl")
                .getDeclaredField("mStopped");
        stoppedField.setAccessible(true);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            List<ViewParent> viewParents = (List<ViewParent>) rootsField.get(windowManager);
            // Filter out inactive view roots
            for (ViewParent viewParent : viewParents) {
                boolean stopped = (boolean) stoppedField.get(viewParent);
                if (!stopped) {
                    viewRoots.add(viewParent);
                }
            }
        } else {
            ViewParent[] viewParents = (ViewParent[]) rootsField.get(windowManager);
            // Filter out inactive view roots
            for (ViewParent viewParent : viewParents) {
                boolean stopped = (boolean) stoppedField.get(viewParent);
                if (!stopped) {
                    viewRoots.add(viewParent);
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return viewRoots;
}

Ответ 5

Я предполагаю, что вы имеете дело с сторонней библиотекой, и у вас нет доступа к объекту диалога.

Вы можете получить представление корня из активности,

Затем вы можете использовать алгоритм обхода дерева, чтобы узнать, можете ли вы достигнуть какого-либо детского представления. Вы не должны доходить до какого-либо из ваших дочерних представлений, если отображается окно предупреждения.

Когда отображается представление предупреждения (проверьте с помощью Ui Automator), единственным элементом, присутствующим в дереве пользовательского интерфейса, является DialogBox/DialogActivity. Вы можете использовать этот трюк, чтобы увидеть, отображается ли диалоговое окно на экране. Хотя это звучит дорого, его можно оптимизировать.

Ответ 6

Вы можете переопределить метод активности onWindowFocusChanged(boolean hasFocus) и отслеживать состояние своей активности.

Обычно, если над вашей деятельностью отображается какой-либо предупреждающий диалог, активность не onPause() и onResume(). Но он теряет фокус на показанном диалоговом окне предупреждения и получает его, когда он отклоняется.