How to check if the current activity has a dialog in front?

泪湿孤枕 提交于 2020-12-28 13:48:42

问题


I am using a third-party library and sometimes it pops up a dialog. Before I finish the current activity, I want to check whether there is a dialog popped up in the current context.

Is there any API for this?


回答1:


You can check it running over the active fragments of that activity and checking if one of them is DialogFragment, meaning that there's a active dialog on the screen:

    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:


I faced a similar problem, and did not want to modify all locations where dialogs were being created and shown. My solution was to look at whether the view I was showing had window focus via the hasWindowFocus() method. This will not work in all situations, but worked in my particular case (this was for an internal recording app used under fairly restricted circumstances).

This solution was not thoroughly tested for robustness but I figured I would post in in case it helped somebody.




回答3:


AFAIK - there is no public API for this.

Recommended way is to have a reference to the dialog, and check for isShowing() and call dismiss() if necessary, but since you're using a third party library, this may not be an options for you.

Your best bet is to check the documentation for the library you use. If that doesn't help, you're out of luck.

Hint: Activity switches to 'paused' state if a dialog pops up. You may be able to 'abuse' this behavior ;)




回答4:


This uses reflection and hidden APIs to get the currently active view roots. If an alert dialog shows this will return an additional view root. But careful as even a toast popup will return an additional view root.

I've confirmed compatibility from Android 4.1 to Android 6.0 but of course this may not work in earlier or later Android versions.

I've not checked the behavior for multi-window modes.

@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:


You can override activity method onWindowFocusChanged(boolean hasFocus) and track the state of your activity.

Normally, if some alert dialog is shown above your activity, the activity does not get onPause() and onResume() events. But it loses focus on alert dialog shown and gains it when it dismisses.




回答6:


I am assuming, you are dealing with third party library and you don't have access to dialog object.

You can get the root view from the activity,

Then you can use tree traversal algorithm to see if you can reach any of the child view. You should not reach any of your child view if alert box is displayed.

When alert view is displayed ( check with Ui Automator ), the only element present in UI tree are from DialogBox / DialogActivity. You can use this trick to see if dialog is displayed on the screen. Though it sounds expensive, it could be optimized.




回答7:


If you are using Kotlin just:

supportFragmentManager.fragments.any { it is DialogFragment }



回答8:


For anyone reading this and wondering how to detect a Dialog above fragment or activity, my problem was that inside my base fragment I wanted to detect if I'm displaying a Dialog on top of my fragment. The dialog itself was displayed from my activity and I didn't want to reach it there, so the solution I came up with (Thanks to all answers related to this kind of question) was to get the view (or you can get the view.rootView) of my fragment and check whether any of its children have the focus or not. If none of its children have no focus it means that there is something (hopefully a Dialog) being displayed above my fragment.

// Code inside my base fragment:
val dialogIsDisplayed = (view as ViewGroup).children.any { it.hasWindowFocus() }


来源:https://stackoverflow.com/questions/11026234/how-to-check-if-the-current-activity-has-a-dialog-in-front

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!