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

hwr*_*kns 41 android android-fragments fragmentmanager android-savedstate onsaveinstancestate

我有时会看到以下用于提交的堆栈跟踪,当用户没有查看活动时(状态保存后)可能会发生这种情况:

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)
Run Code Online (Sandbox Code Playgroud)

看看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);
        }
 }
Run Code Online (Sandbox Code Playgroud)

现在,我想知道是否有任何方法(除了在(保存/恢复)InstanceState中存储类变量)以检查片段是否将以不合需要的状态提交,这样我可以存储事务以供日后使用在适当的时候提交.

azi*_*ian 45

从支持库版本26.0.0 Beta 1开始,新的API可用于FragmentManagerFragment类:

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

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

如果FragmentManager的状态已被其主机保存,则返回true.如果此方法返回true,则不应执行任何将更改已保存状态的操作.例如,任何popBackStack()方法,如popBackStackImmediate()或任何FragmentTransaction使用提交()代替commitAllowingStateLoss()将改变状态,并会导致一个错误.

此API android.app.FragmentManager将从Android O开始提供框架.

  • 似乎非常有帮助 (3认同)

Tom*_*omo 19

由于您没有附加任何示例代码,我只能猜测您在提交事务时使用的是"错误"方法.

因此,FragmentTransaction.commit()您应该使用 FragmentTransaction.commitAllowingStateLoss()而不是使用它.

此外,此google博客文章中有关于此问题(或更改API行为)的报告和变通方法.

  • 你不应该调用FragmentTransaction.commitAllowingStateLoss().只是.这应该是最后的手段. (5认同)
  • 什么时候调用popBackStack?没有popBackStackAllowingStateLoss (3认同)

pea*_*ion 13

不幸的是,如果提交事务没有问题,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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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