从 onContextItemSelected 显示的 DialogFragment 无法在 onPause/onResume 中继续存在

Posted

技术标签:

【中文标题】从 onContextItemSelected 显示的 DialogFragment 无法在 onPause/onResume 中继续存在【英文标题】:DialogFragment displayed from onContextItemSelected doesn't survive onPause/onResume 【发布时间】:2012-12-10 13:30:27 【问题描述】:

我有一个 DialogDragment,我可以显示以下两种方式之一:

1) 通过从其 OnItemClickListener 中点击 ListView 项目

2) 通过激活 ListView 的上下文菜单并选择一个菜单项

执行 #1 在所有生命周期事件下都可以正常工作,但如果我通过 #2 调用它并暂停活动(通过返回 Home)并通过任务切换器恢复它,则不再显示对话框。片段就在那里,我可以旋转设备并显示对话框。

我进行了实验,如果我将 DialogFragment 的显示放入一个延迟至少 1/2 秒的 Handler 中,它可以工作。

以下 sn-p 失败 -- 它显示对话框,但随后暂停/恢复将其隐藏:

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

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

    return consumed;

所以下面的 sn-p 工作。暂停/继续正确显示对话框:

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;

用 0 毫秒或 250 毫秒的延迟代替 300 毫秒的延迟会导致它再次被破坏。这种可重复性 100% 的时间。

这显然是一个可怕的 hack,可能取决于设备速度的常数使情况变得更糟。

有人知道为什么会这样和/或提供更好的解决方案吗?我在这个问题上花了几个小时,这是我能想到的最好的。

【问题讨论】:

我认为这可能与菜单隐藏动画有关。即使是旧的、速度较慢的 Nexus One,300 毫秒的延迟也有效。 如果有机会,请发布一个完整的示例项目来演示这种现象,因为我想看看它。如果它真的是一个平台错误,我们无论如何都需要那个项目来帮助解决问题。此外,这是使用原生 API 级别 11 片段,还是 Android 支持包的反向移植?如果是后者,您确定您使用的是最新版本的 Android Support JAR? 这里是演示问题的示例项目:github.com/androidmoney/Menu-DialogFragment-Test 它发生在本机和支持片段包上。要显示问题,请显示对话框按钮或菜单项。然后暂停(转到主页)并继续(使用应用切换器重新进入应用)。 我遇到了一个非常相似(相同?)的问题:***.com/questions/18730141/… 【参考方案1】:

我可以在 Android 4.2(ARM 模拟器和 Galaxy Nexus)上重现这一点。我无法在 x86 4.1 模拟器、Nexus S (4.1) 和 Motorola RAZR i (4.0) 上重现您的发现。我还可以通过修改我自己的一本图书样本来重现该问题。我使用您的示例提交了一个问题:http://code.google.com/p/android/issues/detail?id=41901 请添加您认为有助于他们诊断问题的任何其他信息。

关于解决方法,如果 300 毫秒有效,那么我们遇到了其中一个可爱的“时间问题”,我不知道你会如何解决它,除非不使用菜单来显示它.例如,对于您的示例应用程序,只需切换到SHOW_AS_ACTION_ALWAYS(因此让它成为操作栏上的一个项目,而不是在溢出菜单中)就足以让DialogFragment 正常运行。希望您有办法调整您的 UI 以弥补这个错误,或者也许有人会想出另一种解决方法并将其发布在此处或问题上。

【讨论】:

谢谢。对我来说,重新设计我的应用程序是不可能的,因为我非常依赖上下文和操作栏溢出菜单中的对话框。【参考方案2】:

我建议在所有暂停时销毁对话框,并根据状态在 onResume 中重新创建,而不管对话框是如何被调用的。如果应用程序在暂停时被操作系统杀死,否则会存在内存泄漏的风险。

要明确回答您的问题,请不要依赖操作系统来维护您的应用状态。

【讨论】:

操作系统保持对话状态很好,期待可见性方面。如果我之后旋转屏幕,对话框会再次显示。我刚刚在 JB 4.2 的 People 应用程序中测试了同样的事情,同样的事情发生了。该对话框在 onPause/onRestore 时消失。这显然是一个 Android 错误。 确实很可能是一个Android错误。我的想法是,您不应该依赖操作系统为您维护状态,因为这样的“错误”可能会出现在不同版本的操作系统中。如果您想期待某个结果,请做一些小事,例如跟踪您自己的状态。许多意想不到的事情可能会突然出现。这只是很好的编程。 好的,谢谢。这可能是一个很好的建议,尽管有点破坏了使用 Fragments 的优势之一。 并非如此。片段旨在成为可重用的可视界面定义。在这种情况下,我们正在处理一个对话框,它使用片段作为其视觉定义,但这与维护视觉状态是分开的——无论对话框是否显示。

以上是关于从 onContextItemSelected 显示的 DialogFragment 无法在 onPause/onResume 中继续存在的主要内容,如果未能解决你的问题,请参考以下文章

OnContextItemSelected() 菜单应用

如何在多片段活动中处理 onContextItemSelected?

从 Springboard 启动应用程序显着延迟

无法从情节提要显式加载视图控制器

如何从数据库中获取数据并在 php 页面上回显? [复制]

从应用程序中获取显式加载的 DLL 的符号