在onActivityResult()中提交FragmentTransaction是否安全?

时间:2017-11-20 22:51:49

标签: android android-fragments android-activity android-fragmentactivity fragmentmanager

多年前,当我尝试在FragmentTransaction回调中提交onActivityResult()时,我在其中一个应用中遇到了问题。谷歌搜索,我发现this question and answer,说

  

在调用onActivityResult()时,活动/片段的状态可能尚未恢复,因此在此期间发生的任何事务都将因此而丢失。

我完全适应了我的应用程序在相同答案中推荐的解决方案,生活很美好。但是,最近的实验表明,事情可能已经发生了变化,现在可能可以安全地从FragmentTransaction内部提交onActivityResult()

The documentation for (support v4) FragmentManager.beginTransaction()将交易的安全窗口定义为:

  

注意:片段事务只能在活动保存其状态之前创建/提交。如果您尝试在FragmentActivity.onSaveInstanceState()之后(以及之后的FragmentActivity.onStartFragmentActivity.onResume()之前提交交易,则会收到错误。

阅读the documentation for onActivityResult(),我看到了

  

当您的活动重新开始时,您会在onResume()之前立即收到此来电。

这让我相信在onActivityResult()执行这些交易应该是安全的,因为onStart()已经被调用,让我进入安全窗口。

我制作了一个应用程序来测试它,并且我成功地看到了我在onActivityResult()内创建和提交的对话框片段。我有相同的应用程序也记录活动生命周期回调,所以我可以检查他们的订单,我看到onStart(),然后onRestoreInstanceState(),然后每次onActivityResult()

我错过了什么吗?或者框架已更改,onActivityResult()现在保证是片段交易的安全位置?此行为是否因API级别而异?

我发现another question and answer似乎以与我相同的方式阅读文档,但两者都超过一年,并且没有特别指onActivityResult()作为交易的安全场所。

1 个答案:

答案 0 :(得分:18)

稍微深入了解消息来源

FragmentManager类中有一个布尔变量,名为mStatedSaved。此变量根据活动的生命周期回调跟踪已保存的状态。 Here's该方法引发众所周知的异常:


    private void checkStateLoss() {
        if (mStateSaved) {
            throw new IllegalStateException(
                    "Can not perform this action after onSaveInstanceState");
        }
        ...
    }

这意味着,只要将此变量更改为false,就可以自由执行片段事务。保存活动状态时,此变量将变为true,即onSaveInstanceState()

回到问题

你说过,之前你在onActivityResult()提交交易时遇到了问题。这应该意味着,之前mStateSaved未被分配false,而且目前已经分配 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { mFragments.noteStateNotSaved(); ... } 。事实上是这样。

此处来自O版本的onActivityResult()实施:


    public void noteStateNotSaved() {
        ...
        mStateSaved = false;
        ...
    }

其中,noteStateNotSaved()会执行以下操作:


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        int index = requestCode>>16;
        if (index != 0) {
            index--;
            if (mFragments.mActive == null || index = mFragments.mActive.size()) {
                Log.w(TAG, "Activity result fragment index out of range: 0x"
                        + Integer.toHexString(requestCode));
                return;
            }
            Fragment frag = mFragments.mActive.get(index);
            if (frag == null) {
                Log.w(TAG, "Activity result no fragment exists for index: 0x"
                        + Integer.toHexString(requestCode));
            } else {
                frag.onActivityResult(requestCode&0xffff, resultCode, data);
            }
            return;
        }

        super.onActivityResult(requestCode, resultCode, data);
    }

相反,你可以看到Jelly Bean发布的onActivityResult()的实现:

mStateSaved

什么都不会改变mFragments.noteStateNotSaved()字段的值,如果提交了事务,则会抛出异常。

事实上,Kit-Kat中的onNewIntent() was introduced行发布了。正如您在Dianne Hackborn制作的commit's comment所看到的那样:

  

ActivityFragment应该清除状态保存的标志   收到onActivityResult()。这可以在活动开始之前发生   恢复了,所以我们可能还没有清除它。还需要做同样的事情   onActivityResult()的事情。

总结

  

现在android:windowSoftInputMode="adjustPan" 是否可以保证片段交易安全?

假设您使用的是2012年10月制作的包含commit 4ccc001的来源 - 是的,这是片段交易的安全场所。