如何从处理程序显示 DialogFragment
我有一个处理程序,它在收到特定消息时显示 DialogFragment。这通常有效,但如果片段已保存,我会收到以下错误:
E/AndroidRuntime(3898):致命异常:main E/AndroidRuntime(3898):java.lang.IllegalStateException:onSaveInstanceState后无法执行此操作 E / AndroidRuntime(3898):在android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1299) E / AndroidRuntime(3898):在android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1310) E / AndroidRuntime(3898):在android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:541) E / AndroidRuntime(3898):在android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:525) E / AndroidRuntime(3898):在android.support.v4.app.DialogFragment.show(DialogFragment.java:123) E / AndroidRuntime(3898):在com.malauzai.app.BaseActivity $ 2.handleMessage(BaseActivity.java:72) E / AndroidRuntime(3898):在android.os.Handler.dispatchMessage(Handler.java:99)
现在,我知道这是预期的,基于 FragmentManager.beginTransaction 的 Javadoc:
注意:片段事务只能在活动保存其状态之前创建/提交。如果您尝试在 Activity.onSaveInstanceState() 之后(在后续 Activity.onStart 或 Activity.onResume() 之前提交事务,您将收到错误。这是因为框架负责将当前片段保存在状态中) ,如果在保存状态后进行更改,则这些更改将会丢失。
我的问题是我不知道如何阻止它,我已尝试调用 Handler.removeMessages()
。 onPause()
,但它仍然发生,我尝试在 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;
}
}
};
I have a Handler which displays a DialogFragment when it receives a particular message. This usually works, but if the fragment has already been saved, I get the following error:
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)
Now, I know that this is expected, based on the Javadoc for FragmentManager.beginTransaction:
Note: A fragment transaction can only be created/committed prior to an activity saving its state. If you try to commit a transaction after Activity.onSaveInstanceState() (and prior to a following Activity.onStart or Activity.onResume(), you will get an error. This is because the framework takes care of saving your current fragments in the state, and if changes are made after the state is saved then they will be lost.
My problem is that I can't tell how to prevent it. I've tried calling Handler.removeMessages()
on onPause()
, but it still occurs. I've tried setting a flag in onSaveInstanceState()
and not showing the fragment if it's set, but it still occurs. This seems like a pretty common problem, but I can't come up with a solution that works. Basically, how do I know that the fragment has already been saved?
BTW, this occurs on my BaseActivity (extends FragmentActivity), but each activity has its own handler, so I don't think this should be an issue.
My last thought is using Fragment.commitAllowingStateLoss()
, but that seems like a hack.
EDIT:
Here's the code that's causing me problems:
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;
}
}
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我在回答中假设您正在使用 FragmentManager 并通过带有标签(或 ids)的 FragmentTransacts 添加片段。
所以基本上在你的
BaseActivity
中你可以做这样的事情I assume in my answer that you are using FragmentManager and add Fragments through FragmentTransacts with tags (or ids).
so basically inside your
BaseActivity
you could just do something like this