DialogFragment displayed from onContextItemSelected doesn't survive onPause/onResume
Asked Answered
D

2

8

I have a DialogDragment which I can show one of two ways:

1) By tapping on a ListView item from its OnItemClickListener

2) By activating a the ListView's context menu and selecting a menu item

Doing #1 works fine under all lifecycle events, but if I invoke it via #2 and I pause the activity (by going Home) and the resuming it via the task switcher, the dialog is no longer displayed. The fragment is there, and I can rotate the device and show the dialog.

I experimented, and if I put the showing of the DialogFragment into a Handler with a delay of at least 1/2 seconds, it works.

The following snippet fails -- it shows the dialog, but then pause/resume hides it:

public boolean onContextItemSelected(android.view.MenuItem item) {
    boolean consumed = false;

    switch (item.getItemId()) {
    case R.id.menu_item:
        showMyDialogFragment();
        consumed = true;
        break;
    }

    return consumed;
}

So the following snippet works. Pause/resume display the dialog again correctly:

public boolean onContextItemSelected(android.view.MenuItem item) {
    boolean consumed = false;

    switch (item.getItemId()) {
    case R.id.menu_item:
        new Handler().postDelayed(new Runnable() {
            public void run() {
                showMyDialogFragment();
            }
        }, 300);

        consumed = true;
        break;
    }

    return consumed;
}

Replacing the 300ms second delay with a 0ms or 250ms delay causes it to be broken again. This repeatable 100% of the time.

This is a terrible hack obviously, made worse by the constant that's probably depends on the speed of the device.

Anybody know why this is going on and/or offer a better solution? I spent hours on this issue and this is the best I could come up with.

Dimorph answered 24/12, 2012 at 1:12 Comment(4)
I think this may have something to do with the menu hiding animation. Even of an old, slow Nexus One, the 300ms delay is working.Dimorph
If you get a chance, post a complete sample project that demonstrates this phenomenon, as I'd like to take a peek at it. If it's really a platform bug, we'll need that project anyway to help get the problem fixed. Also, is this using native API Level 11 fragments, or the Android Support package's backport? If the latter, are you sure that you are on the latest version of the Android Support JAR?Blaspheme
Here's the sample project demonstrating the issue: github.com/androidmoney/Menu-DialogFragment-Test It happens both on native and on the support fragment package. To show the problem, display the dialog either the button or the menu item. Then pause (go to Home) and resume (reenter app using app switcher).Dimorph
I am experiencing a very similar (same?) issue: #18730641Impious
B
4

I can reproduce this on Android 4.2 (ARM emulator and Galaxy Nexus). I am unable to reproduce your findings on an x86 4.1 emulator, a Nexus S (4.1), and a Motorola RAZR i (4.0). I can also reproduce the problem by modifying one of my own book samples. I filed an issue on it, using your sample: http://code.google.com/p/android/issues/detail?id=41901 Please add any other information you think would help them diagnose the problem.

With respect to a workaround, if 300ms works, then we have one of those lovely "timing issues", and I haven't the foggiest idea how you'd work around it, short of not using a menu to display it. For example, with your sample app, simply switching to SHOW_AS_ACTION_ALWAYS (and therefore having it be an item on the action bar rather than in an overflow menu) is sufficient to have the DialogFragment behave properly. Hopefully, you'll have a way of adjusting your UI to compensate for this bug, or perhaps somebody will cook up another workaround and post it here or on the issue.

Blaspheme answered 25/12, 2012 at 19:39 Comment(1)
Thanks. For me, it will be impossible to redesign my app as I am so reliant on dialogs both from context and action bar overflow menus.Dimorph
V
2

I would recommend destroying the dialog on all pauses and recreate in onResume depending on state regardless of how the dialog is invoked. To do otherwise risks a memory leak if the app is killed by the OS in while paused.

To explicitly answer your question, don't rely on the OS to maintain your app state.

Villainy answered 24/12, 2012 at 1:23 Comment(4)
The OS maintains the dialog state just fine, expect the visibility aspect. If I rotate the screen afterwards, the dialog is shown again. I just tested the same thing in the People app in JB 4.2, and the same thing happens. The dialog disappears on an onPause/onRestore. This is clearly an Android bug.Dimorph
Indeed it very well might be an Android bug. My thought is that you should not rely on the OS maintain state for you as just such "bugs" can emerge in differing version of the OS. If you want to expect a certain outcome, do the small things like keep track of your own state. Many unexpected things can crop up. It's just good programming.Villainy
Ok, thanks. That's probably a good advice, though kind of defeats one of the advantages of using Fragments.Dimorph
Not really. Fragments are intended to be reusable visual interface definitions. In this situation, we are dealing with a dialog, which uses a fragment for its visual definition, but that is separate from the maintaining the visual state - whether the dialog is displayed or not.Villainy

© 2022 - 2024 — McMap. All rights reserved.