如何从Handler中显示DialogFragment

5
我有一个Handler,当它接收到特定的消息时会显示一个DialogFragment。通常情况下这个方法是有效的,但如果该片段已经被保存了,则会出现以下错误:
E/AndroidRuntime( 3898): FATAL EXCEPTION: main E/AndroidRuntime( 3898): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState E/AndroidRuntime( 3898): at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1299) E/AndroidRuntime( 3898): at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1310) E/AndroidRuntime( 3898): at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:541) E/AndroidRuntime( 3898): at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:525) E/AndroidRuntime( 3898): at android.support.v4.app.DialogFragment.show(DialogFragment.java:123) E/AndroidRuntime( 3898): at com.malauzai.app.BaseActivity$2.handleMessage(BaseActivity.java:72) E/AndroidRuntime( 3898): at android.os.Handler.dispatchMessage(Handler.java:99)
现在,根据FragmentManager.beginTransaction的Javadoc,我知道这是预期的:
注意:只能在活动保存其状态之前创建/提交片段事务。如果在Activity.onSaveInstanceState()之后(并在以下Activity.onStart或Activity.onResume()之前)尝试提交事务,则会出错。这是因为框架会负责在状态中保存当前片段,如果在保存状态后进行更改,则它们将丢失。
我的问题是我不知道如何防止这种情况发生。我已经尝试在onPause()中调用Handler.removeMessages(),但仍然出现了错误。我已经尝试在onSaveInstanceState()中设置一个标志,如果设置了就不显示片段,但仍然出现了错误。这似乎是一个很常见的问题,但我找不到解决方法。基本上,我如何知道该片段已经被保存?
顺便说一下,这发生在我的BaseActivity(扩展FragmentActivity)上,但每个活动都有自己的处理程序,所以我认为这不应该是一个问题。
我最后的想法是使用Fragment.commitAllowingStateLoss(),但那似乎是一个hack。
编辑:以下是引起问题的代码:
private final Handler mTimerHandler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
        switch (msg.what) {
        case TIMER_MESSAGE_LOGOUT_WARNING:
            // throws IllegalStateException if fragment is already saved
            new LogoutWarningDialog().show(getSupportFragmentManager(),
                    "dialog");
            break;
        }
      }
};

通常情况下,突然在随机时间显示对话框被认为是糟糕的用户体验,因此在你尝试艰难地寻找解决方法之前,我建议重新考虑你的设计。请参阅这篇关于该主题的博客文章获取更多信息。 - Alex Lockwood
1个回答

1

我在回答中假设您正在使用FragmentManager,并通过标签(或ID)添加Fragments。因此,基本上在您的BaseActivity内,您可以像这样操作:

FragmentManager manager = getFragmentSupportedManager();
Fragment fragmentIWannaKnowIfexists = manager.findFragmentByTag("Tag I used to create this Fragment inside FragmentTrasnsaction")
// or manager.findFragmentById(ID_FROM_LAYOUT)
if(fragmentIWannaKnowIfexists != null){
    //we have this Fragment already
} else {
    // this Fragment was not added already
}

不,我试图添加的片段从未存在过。它是一个FragmentDialog,只有在我收到消息时才会创建。我会添加一些代码。 - Shawn Lauzon
2
虽然我从未见过这个问题导致这个错误消息,但你绝对应该尝试 Rafael 建议的方法。如果你说“它从未存在过”,也许存在其他对话框。将你的标签从“对话框”更改为“这个特定的对话框”。 - Pedro Loureiro
很好。我有几个带有相同标签的不同对话框。好的回答/评论。 - Knossos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接