About the pit of Alert Dialog

When we need to know whether AlertDialog is being displayed, we used the isShowing() method to hide dialog. There are three main ways to hide dialog: cancel(), hide(), dismiss(). But instead of calling any of these three methods, dialog. isShowing() returns false.


We need to look at the source code:


Since we want to call the isShowing() method to determine whether dialog is being displayed, we must first look at the implementation of this method:

    /**
     * @return Whether the dialog is currently showing.
     */
    public boolean isShowing() {
        return mShowing;
    }

Simply, it returns a boolean variable that is clearly used to identify whether dialog is being displayed.

To know whether all three methods can make the isShowing() method return false, we need to see how the three methods affect the mShowing variable.


First, let's look at the source code of cancel method:

    /**
     * Cancel the dialog.  This is essentially the same as calling {@link #dismiss()}, but it will
     * also call your {@link DialogInterface.OnCancelListener} (if registered).
     */
    @Override
    public void cancel() {
        if (!mCanceled && mCancelMessage != null) {
            mCanceled = true;
            // Obtain a new message so this dialog can be re-used
            Message.obtain(mCancelMessage).sendToTarget();
        }
        dismiss();
    }

You can see that the dismiss method is finally invoked.


Next, look at the dismiss method:

    /**
     * Dismiss this dialog, removing it from the screen. This method can be
     * invoked safely from any thread.  Note that you should not override this
     * method to do cleanup when the dialog is dismissed, instead implement
     * that in {@link #onStop}.
     */
    @Override
    public void dismiss() {
        if (Looper.myLooper() == mHandler.getLooper()) {
            dismissDialog();
        } else {
            mHandler.post(mDismissAction);
        }
    }

The dismissDialog() method is called by the dismissDialog(), so we have to look at the source code of the dismissDialog() method:

    void dismissDialog() {
        if (mDecor == null || !mShowing) {
            return;
        }

        if (mWindow.isDestroyed()) {
            Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!");
            return;
        }

        try {
            mWindowManager.removeViewImmediate(mDecor);
        } finally {
            if (mActionMode != null) {
                mActionMode.finish();
            }
            mDecor = null;
            mWindow.closeAllPanels();
            onStop();
            mShowing = false;

            sendDismissMessage();
        }
    }

It seems obvious that cancel() and dismiss() both assign false s to the mShowing variable.


So what about the hide() method? Take a look at the source code:

    /**
     * Hide the dialog, but do not dismiss it.
     */
    public void hide() {
        if (mDecor != null) {
            mDecor.setVisibility(View.GONE);
        }
    }

The hide() method doesn't call any other method, it's just three lines short, and it just sets dialog to GONE... Therefore, the hide() method does not change the value of mShowing.


Looking at this, we can see why I said that not all three methods can get the isShowing method to return the exact value.


So, if you need to use the isShowing method to determine whether the dialog is being displayed, remember not to use the hide method when hiding the dialog.


Added by mp96brbj on Sat, 25 May 2019 01:06:48 +0300