DialogFrag#show()来自片段抛出“IllegalStateException:onSaveInstanceState后无法执行此操作”

为了清楚起见,我已经阅读了关于“IllegalStateException:在onSaveInstanceState之后无法执行此操作”的十几个SO问题,我已经阅读了Alex Lockwood的博客文章http://www.androiddesignpatterns.com/2013/08/片段事务提交状态-loss.html

所以我不是盲目地问这个。

我有一个非常简单的用例案例, 涉及AsyncTask或任何后台处理。

我有一个包含按钮的片段。 在按钮的onClickListener上,我创建了一个DialogFragment并显示它。

public final class OverviewFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.overview_fragment, container, false); startNewGameButton = (Button) view.findViewById(R.id.buttonNewGame); startNewGameButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { final NewGameFragment dialogFrag = NewGameFragment.create(getApplication()); dialogFrag.show(getFragmentManager(), NewGameFragment.FRAGMENT_TAG); } }); } 

[NewGameFragment]

 public final class NewGameFragment extends DialogFragment { public static final String FRAGMENT_TAG = "NewGameFragment"; private static final String MESSAGE = "message"; public static NewGameFragment create(Context context) { final AppsPreferences prefs = new AppPreferences(context); final int startOption = prefs.getGameStartOption(); final Bundle bundle = new Bundle(); bundle.putString(MESSAGE, getMessage(context, startOption)); final NewGameFragment fragment = new NewGameFragment(); fragment.setArguments(bundle); return fragment; } @Override public final Dialog onCreateDialog(Bundle savedInstanceState) { final String message = getArguments().getString(MESSAGE); final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) .setTitle(R.string.progress_startGame_title) .setMessage(message); builder.setPositiveButton(R.string.progress_startGame_raceButton, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { new RaceAction().execute(); } }); builder.setNegativeButton(R.string.progress_startGame_eventButton, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { new EventAction().execute(); } }); final Dialog dialog = builder.create(); dialog.setCanceledOnTouchOutside(false); // Whether clicking outside the dialog closes the dialog. return dialog; } } 

[堆栈跟踪]

 java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.void checkStateLoss()(SourceFile:1365) at android.support.v4.app.FragmentManagerImpl.void enqueueAction(java.lang.Runnable,boolean)(SourceFile:1383) at android.support.v4.app.BackStackRecord.int commitInternal(boolean)(SourceFile:636) at android.support.v4.app.BackStackRecord.int commit()(SourceFile:615) at android.support.v4.app.DialogFragment.void show(android.support.v4.app.FragmentManager,java.lang.String)(SourceFile:138) at au.com.xandar.thegame.overview.OverviewFragment$1.void onClick(android.view.View)(SourceFile:160) at android.view.View.performClick(View.java:4162) at android.view.View$PerformClick.run(View.java:17082) at android.os.Handler.handleCallback(Handler.java:615) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4867) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1007) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:774) at dalvik.system.NativeStart.main(Native Method) 

NB片段和DialogFragment都来自support-v4:21.0.0

我在一系列运行4.4的设备上看到了这一点。 但至少有一个实例发生在运行5.0的Nexus 7上。

我自己无法复制这个。 甚至没有通过在onClick中引入人工延迟并尝试旋转,返回,回家。

因为FragmentTransaction (对于DialogFrag#show() )是直接从onClick()在UI线程上创建和提交的,所以Fragment如何已经过了onSaveInstanceState()

这是否意味着我需要在每个用户输入开始时检查活动生命周期的状态? – 非常糟糕(Lifecycle意味着要为我处理。如果Activity已经过了onPause()我不应该接收用户输入)

这是否意味着我需要在执行用户输入期间检查每个语句之前的活动生命周期的状态? – 坏了!!

我该怎么做才能阻止这种情况发生?

更多信息:

在野外跑了好几天后,我可以断然说getChildFragmentManager()不是解决方案。

以下Android版本发生故障:

  • 4.4.2 90%
  • 4.4.4 5%
  • 5.0 5%

好吧,据我所知,这是AOSP中的一个错误 ,因为我也从纯Android堆栈中看到了这个实例(即我的代码根本没有)。

所以看起来在Activity / Fragment生命周期中存在一个线程问题,其中UI线程可以优先响应按钮点击事件/片段已经保存它的状态。

到目前为止我的工作100%成功是捕获IllegalStateException并安排对话框显示下次使用PauseHandler激活Activity / Fragment时https://stackoverflow.com/a/25322330/493682