I don't use managed dialogs at all -- not only don't they work in
certain cases (like in a TabActivity), I think the whole system of
having to maintain global dialog ids is a pain.  In my very large app,
I ended up with a DialogIds global enum, which I hated.  I still have
the same issue with request ids for startActivityForResult(), but I
don't have a solution for that yet.

Here's an example of what I do, a simple MessageDialog class.  It took
me a while to perfect the mechanism, but it works great with screen
orientation changes and activity save/restore.  Also, I am purposely
not saving a reference to Context, to avoid any possible leaks.   The
interesting part is how a new Listener is passed in to restoreState as
the listener is the only state that cannot be recrated reliably (the
target can be a different object if the Activity was destroyed/
resumed)


public class MessageDialog
{
    public enum MessageDialogButton
    {
        POSITIVE,
        NEGATIVE,
        NEUTRAL
    }


    private static final String KEY_DIALOG_SHOWING       =
"_dialog_showing";      //$NON-NLS-1$
    private static final String KEY_DIALOG_DATA          =
"_dialog_data";         //$NON-NLS-1$
    private static final String KEY_TITLE                =
"_title";               //$NON-NLS-1$
    private static final String KEY_MESSAGE              =
"_message";             //$NON-NLS-1$
    private static final String KEY_ICON                 =
"_icon";                //$NON-NLS-1$
    private static final String KEY_POSITIVE_BUTTON_TEXT =
"_positive_button_text"; //$NON-NLS-1$
    private static final String KEY_NEGATIVE_BUTTON_TEXT =
"_negative_button_text"; //$NON-NLS-1$
    private static final String KEY_NEUTRAL_BUTTON_TEXT  =
"_neutral_button_text"; //$NON-NLS-1$

    protected CharSequence      baseKey;
    Dialog                      dialog;
    MessageDialogListener       listener;
    private CharSequence        title;
    private CharSequence        message;
    private int                 icon;
    private CharSequence        positiveButtonText;
    private CharSequence        negativeButtonText;
    private CharSequence        neutralButtonText;


    public MessageDialog(CharSequence tag)
    {
        this.baseKey = this.getClass().getName() + '_' + tag;
    }


    public void saveState(Bundle bundle)
    {
        boolean dialogShowing = isShowing();
        bundle.putBoolean(this.baseKey + KEY_DIALOG_SHOWING,
dialogShowing);
        if (dialogShowing)
        {
            bundle.putBundle(this.baseKey + KEY_DIALOG_DATA,
this.dialog.onSaveInstanceState());
            bundle.putCharSequence(this.baseKey + KEY_TITLE,
this.title);
            bundle.putCharSequence(this.baseKey + KEY_MESSAGE,
this.message);
            bundle.putInt(this.baseKey + KEY_ICON, this.icon);
            bundle.putCharSequence(this.baseKey +
KEY_POSITIVE_BUTTON_TEXT, this.positiveButtonText);
            bundle.putCharSequence(this.baseKey +
KEY_NEGATIVE_BUTTON_TEXT, this.negativeButtonText);
            bundle.putCharSequence(this.baseKey +
KEY_NEUTRAL_BUTTON_TEXT, this.neutralButtonText);
        }
    }


    public void restoreState(Context context, MessageDialogListener
_listener, Bundle bundle)
    {
        this.listener = _listener;

        boolean dialogShowing = bundle.getBoolean(this.baseKey +
KEY_DIALOG_SHOWING);
        if (dialogShowing)
        {
            this.title = bundle.getCharSequence(this.baseKey +
KEY_TITLE);
            this.message = bundle.getCharSequence(this.baseKey +
KEY_MESSAGE);
            this.icon = bundle.getInt(this.baseKey + KEY_ICON);
            this.positiveButtonText =
bundle.getCharSequence(this.baseKey + KEY_POSITIVE_BUTTON_TEXT);
            this.negativeButtonText =
bundle.getCharSequence(this.baseKey + KEY_NEGATIVE_BUTTON_TEXT);
            this.neutralButtonText =
bundle.getCharSequence(this.baseKey + KEY_NEUTRAL_BUTTON_TEXT);

            showDialog(context, checked);

            Bundle dialogData = bundle.getBundle(this.baseKey +
KEY_DIALOG_DATA);
            this.dialog.onRestoreInstanceState(dialogData);
        }
    }


    public void show(Context context, MessageDialogListener _listener,
CharSequence _title, CharSequence _message, int _icon, CharSequence
_positiveButtonText, CharSequence _negativeButtonText, CharSequence
_neutralButtonText)
    {
        this.listener = _listener;
        this.title = _title;
        this.message = _message;
        this.icon = _icon;
        this.positiveButtonText = _positiveButtonText;
        this.negativeButtonText = _negativeButtonText;
        this.neutralButtonText = _neutralButtonText;

        showDialog(context);
    }


    public void dismissIfShowing()
    {
        if (isShowing())
            this.dialog.dismiss();

        this.listener = null;
    }


    protected void showDialog(Context context)
    {
        Builder builder = new Builder(context);
        builder.setTitle(this.title);
        builder.setCancelable(false);
        builder.setView(bodyView);
        builder.setMessage(this.message);

        if (this.icon != 0)
            builder.setIcon(this.icon);

        if (this.positiveButtonText != null)
            builder.setPositiveButton(this.positiveButtonText, new
OnClickListener()
            {
                public void onClick(DialogInterface _dialog, int
which)
                {
                    // Mark it not showing, no need to call .dismiss()
as it has been done already by AlertDialog
                    MessageDialog.this.dialog = null;

                    if (MessageDialog.this.listener != null)
 
MessageDialog.this.listener.onClose(MessageDialog.this,
MessageDialogButton.POSITIVE);
                }
            });

        if (this.negativeButtonText != null)
            builder.setNegativeButton(this.negativeButtonText, new
OnClickListener()
            {
                public void onClick(DialogInterface _dialog, int
which)
                {
                    MessageDialog.this.dialog = null;

                    if (MessageDialog.this.listener != null)
 
MessageDialog.this.listener.onClose(MessageDialog.this,
MessageDialogButton.NEGATIVE);
                }
            });

        if (this.neutralButtonText != null)
            builder.setNeutralButton(this.neutralButtonText, new
OnClickListener()
            {
                public void onClick(DialogInterface _dialog, int
which)
                {
                    MessageDialog.this.dialog = null;

                    if (MessageDialog.this.listener != null)
 
MessageDialog.this.listener.onClose(MessageDialog.this,
MessageDialogButton.NEUTRAL);
                }
            });

        this.dialog = builder.show();
    }


    protected boolean isShowing()
    {
        return (this.dialog != null);
    }


    public interface MessageDialogListener
    {
        void onClose(MessageDialog dialog, MessageDialogButton
button);
    }
}



Then your Activity would look something like this:



public class MyActivity extends Activity
{
    private MessageDialog  myDialog  = new MessageDialog("myDialog");


    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        if (savedInstanceState != null)
            this.myDialog.restoreState(this, createMyDialogListener(),
savedInstanceState);
    }


    protected void onDestroy()
    {
        super.onDestroy();

        this.myDialog.dismissIfShowing();
    }


    protected void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);

        this.myDialog.saveState(outState);
    }


    private void showMyDialog()
    {
            this.myDialog.show(this, createMyDialogListener(),
"Message title", "Message to show", 0, "Ok", "Cancel", null);
    }


    private MessageDialogListener createMyDialogListener()
    {
        return new MessageDialogListener()
        {
            public void onClose(MessageDialog dialog,
MessageDialogButton button)
            {
                if (button == MessageDialogButton.POSITIVE)
                   doOk();
                else
                   doCancel();
            }
        };
    }
}


On Jun 25, 11:58 pm, TreKing <[email protected]> wrote:
> On Wed, Jun 23, 2010 at 8:02 AM, Surfer <[email protected]> wrote:
> > Hi, built a simple app that displays an alertDialog with two buttons.
> > The problem is it's not getting dismissed when i change orientation.
> > After change i get a leak warning on debugger and the dialog appears
> > twice(pressing back hides the first dialog, only a second back
> > dismisses it completely). Any ideas?
>
> OnCreate makes dialog #1 which is managed by the activity. So far so good.
>
> You rotate, forcing onCreate to get called again which creates a new dialog,
> #2.
>
> Meanwhile dialog #1 is being managed for you and is being re-shown. Now you
> have 2 dialogs.
>
> Since they have the same ID, the second is probably overriding the first in
> the Activity's management system causing a leak of the first.
>
> Simple fix: check if you Bundle is null in onCreate. If it is, you're a
> fresh start and can show a dialog for the first time. If it's not, you're
> being recreated and your managed dialog will show on it's own, so you don't
> have to do anything.
>
> ---------------------------------------------------------------------------­----------------------
> TreKing - Chicago transit tracking app for Android-powered 
> deviceshttp://sites.google.com/site/rezmobileapps/treking

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

Reply via email to