在提交FragmentTransaction之前检查状态是否保存

我有时会看到下面的堆栈跟踪提交,当用户没有看到活动(在状态被保存之后)时可能发生:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1327) at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1338) at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595) at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574) 

看一下Android的源代码,这是非常重要的:

 private void checkStateLoss() { if (mStateSaved) { throw new IllegalStateException( "Can not perform this action after onSaveInstanceState"); } if (mNoTransactionsBecause != null) { throw new IllegalStateException( "Can not perform this action inside of " + mNoTransactionsBecause); } } 

现在,我想知道是否有任何方法(除了在(保存/恢复)InstanceState中存储一个类变量)来检查一个片段是否将被提交到一个不希望的状态,这样我可以存储事务以便以后使在适当的时候提交。

由于您没有附加任何示例代码,所有我可以猜测的是,您提交事务时使用“错误”的方法。

所以,而不是使用FragmentTransaction.commit() ,你应该使用FragmentTransaction.commitAllowingStateLoss() 。

此外,在这个谷歌博客文章中有关于这个问题的报告和解决方法(或更改API行为)。

从支持库版本26.0.0 Beta 1开始,在FragmentManagerFragment类中提供了一个新的API:

FragmentManagerFragment有一个isStateSaved()方法来允许查询是否允许一个事务没有状态丢失。 这在执行任何事务之前检查处理onClick()事件时特别有用。

来自android.support.v4.app.FragmentManager#isStateSaved()文档:

如果FragmentManager的状态已经被主机保存,则返回true 。 如果此方法返回true,则不应执行任何会更改已保存状态的操作。 例如,任何popBackStack()方法(如popBackStackImmediate())或任何使用commit()而不是commitAllowingStateLoss()FragmentTransaction都会更改状态,并会导致错误。

这个API将从Android android.app.FragmentManager开始提供框架的android.app.FragmentManager

不幸的是Android Fragment没有提供API检查,如果交易没有问题。

但是我们可以在附加的活动中添加一个布尔字段来帮助我们检查。 请参考以下代码。

 public class GlobalBaseActivity extends FragmentActivity { private boolean mAllowCommit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mAllowCommit = true; } @Override protected void onSaveInstanceState(Bundle outState) { mAllowCommit = false; super.onSaveInstanceState(outState); } @Override protected void onResumeFragments() { mAllowCommit = true; super.onResumeFragments(); } public boolean allowFragmentCommit() { return mAllowCommit; } public void callbackOnEvent() { if (allowFragmentCommit()){ getFragmentManager().beginTransaction().add(new YourFragment(), TAG).commit(); } } } 

至于为什么选择onResumeFragment()作为允许交易指标,请参考这个好博客 。 它详细解释了着名的IllegalStateException。

您应该只在这些方法OnCreate,OnResumeFragments,OnPostResume中调用方法提交。 细节你可以在这里阅读片段交易和活动状态损失

看到我也有这个问题,我找不到解决方案在哪里。 我尝试了一下解决方法,就是这样。 而是从一个处理程序进行片段事务。 应该用2000毫秒的DELAY调用处理程序。 例如。 在调用makeTransaction

 void makeTransaction() { handler.sendEmptyMessageDelayed(0,2000); } void actuallyMakeTransaction() { // transaction code } Handler handler = new Handler() { void handleMessage(Message msg) { actuallyMakeTransaction(); } } 

它解决了我的问题

RuntimeExceptions(和IllegalStateException是其中之一)通常意味着你的代码是不正确的如何试图实现的东西。 试图处理这种异常(例如通过捕捉)也是错误的。 你的代码永远不会像Android那样在你身上抛出异常。

如果您使用处理程序发布或发送消息以供将来处理,则需要在退出恢复状态之前清除队列。 你也不能从Activity中启动AsyncTask,并在onPostExecute中提交事务,因为用户可以从你的Activity中返回。 你需要取消它,并检查它是否被取消。

有很多这样的例子,都是由“临时性”的内存泄漏引起的,就像我喜欢称它们一样。

基本上你的代码是坏的,没有提供它,这是不可能的。

在这种情况下, ft.commitAllowingStateLose()是最好的选择。 但是,如前所述,不能保证你们的国家会坚持下去。

下面是一个利用最新的isStateSaved()FragmentManager方法的Kotlin示例: https ://proandroiddev.com/kotlin-extensions-to-commit-fragments-safely-de06218a1f4