There have been numerous threads (here and elsewhere) and bugs about
issues with managed dialogs and configuration changes (orientation or
keyboard slides).  However, I haven't found exact mention of this
specific issue and I wonder if it could by the cause of some of the
other problems that folks have.

What I am seeing is specifically a bug in
Activity.restoreManagedDialogs() .  It ignores the existence of any
existing managed dialogs (held in mManagedDialogs) and creates a new
SparseArray to hold the restored dialogs.

Here are the steps to see the problem (I can write up some sample code
if someone really needs it).

1. In onCreate() or onStart() of your activity, show a managed dialog
(perhaps an indeterminate progress dialog) using
Activity.showDialog() .
2. Dismiss (not remove) the dialog by calling Activity.dismissDialog()
using whatever means you desire.  In my particular case it was a
separate thread calling back into the activity but hitting the back
button should work as well.
3. Change orientation on your device.  Your dialog will display (as
expected) but you cannot dismiss it using Activity.dismissDialog().

The reason:
The call to showDialog() in onCreate() creates a new dialog and stores
it in a newly initialized mManagedDialogs.  This occurs before
Activity.restoreManagedDialogs() which happens between onStart() and
onResume().  When restoreManagedDialogs() executes it reinitializes
mManagedDialogs without any checks.  Later, when the code calls
dismissDialog() with the dialog id, it finds a Dialog object but it is
the new one (created in restoreManagedDialogs) and not the one that is
actually being shown (created in onCreate).  The code then fails to
dismiss the displayed dialog.

I'm of the mind that this is a flat out bug but I wanted to see if
anyone else disagreed before I wasted developer time with a filed
bug.  The only counter-argument I can see is that we should never call
Activity.showDialog() before onResume() but that seems limiting and
arbitrary nor can I find any mention of that in documentation.



Here you can see the current code (which appears to be the same at
least back to 1.6):

    private void restoreManagedDialogs(Bundle savedInstanceState) {
        final Bundle b =
savedInstanceState.getBundle(SAVED_DIALOGS_TAG);
        if (b == null) {
            return;
        }

        final int[] ids = b.getIntArray(SAVED_DIALOG_IDS_KEY);
        final int numDialogs = ids.length;
        mManagedDialogs = new SparseArray<Dialog>(numDialogs);
        for (int i = 0; i < numDialogs; i++) {
            final Integer dialogId = ids[i];
            Bundle dialogState =
b.getBundle(savedDialogKeyFor(dialogId));
            if (dialogState != null) {
                // Calling onRestoreInstanceState() below will invoke
dispatchOnCreate
                // so tell createDialog() not to do it, otherwise we
get an exception
                final Dialog dialog = createDialog(dialogId,
dialogState);
                mManagedDialogs.put(dialogId, dialog);
                onPrepareDialog(dialogId, dialog);
                dialog.onRestoreInstanceState(dialogState);
            }
        }
    }



And my proposed fix:

    private void restoreManagedDialogs(Bundle savedInstanceState) {
        final Bundle b =
savedInstanceState.getBundle(SAVED_DIALOGS_TAG);
        if (b == null) {
            return;
        }

        final int[] ids = b.getIntArray(SAVED_DIALOG_IDS_KEY);
        final int numDialogs = ids.length;
        if (mManagedDialogs == null) {
            mManagedDialogs = new SparseArray<Dialog>(numDialogs);
        }
        for (int i = 0; i < numDialogs; i++) {
            final Integer dialogId = ids[i];
            Bundle dialogState =
b.getBundle(savedDialogKeyFor(dialogId));
            if (dialogState != null) {
                // Calling onRestoreInstanceState() below will invoke
dispatchOnCreate
                // so tell createDialog() not to do it, otherwise we
get an exception
                Dialog dialog = mManagedDialogs.get(id);
                if (dialog == null) {
                    Dialog dialog = createDialog(dialogId,
dialogState);
                    mManagedDialogs.put(dialogId, dialog);
                }
                onPrepareDialog(dialogId, dialog);
                dialog.onRestoreInstanceState(dialogState);
            }
        }
    }

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

To unsubscribe, reply using "remove me" as the subject.

Reply via email to