Android 在onActivityResult()中提交碎片事务是否安全?

Android 在onActivityResult()中提交碎片事务是否安全?,android,android-fragments,android-activity,android-fragmentactivity,fragmentmanager,Android,Android Fragments,Android Activity,Android Fragmentactivity,Fragmentmanager,几年前,当我试图在我的onActivityResult()回调中提交FragmentTransaction时,我的一个应用程序遇到了问题。搜索一下,我发现,上面写着 在调用activityResult()时,活动/片段的状态可能尚未恢复,因此在此期间发生的任何事务都将因此丢失 我最终采用了我的应用程序在相同答案中推荐的解决方案,生活很好。然而,最近的实验表明,情况可能已经发生了变化,现在可以从内部onActivityResult()安全地提交碎片事务 将事务的安全窗口定义为: 注意:片段事务只能

几年前,当我试图在我的
onActivityResult()回调中提交
FragmentTransaction
时,我的一个应用程序遇到了问题。搜索一下,我发现,上面写着

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

我最终采用了我的应用程序在相同答案中推荐的解决方案,生活很好。然而,最近的实验表明,情况可能已经发生了变化,现在可以从内部
onActivityResult()
安全地提交
碎片事务

将事务的安全窗口定义为:

注意:片段事务只能在活动保存其状态之前创建/提交。如果您尝试在
FragmentActivity.onSaveInstanceState()
(在以下
FragmentActivity.onStart
FragmentActivity.onResume()
之前)提交事务,您将收到一个错误

阅读,我明白了

当您的活动重新启动时,您将在
onResume()之前立即收到此呼叫

这让我相信,在
onActivityResult()
中执行这些事务应该是安全的,因为
onStart()
已经被调用,将我置于安全窗口中

我制作了一个应用程序来测试这一点,我成功地看到了我在
onActivityResult()
中创建和提交的对话框片段。我还让同一个应用程序记录了活动生命周期回调,以便检查它们的顺序,我看到了
onStart()
,然后是
onrestoreinnstanceState()
,然后是
onActivityResult())
每次

我是否遗漏了什么?或者框架是否已更改,并且
onActivityResult()
现在已被保证为片段事务的安全场所?此行为是否因API级别而异


我发现他们阅读文档的方式似乎与我相同,但他们都已经有一年多的历史了,而且都没有特别提到
onActivityResult()
是一个安全的交易场所。

稍微深入了解一下源代码

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


    private void checkStateLoss() {
        if (mStateSaved) {
            throw new IllegalStateException(
                    "Can not perform this action after onSaveInstanceState");
        }
        ...
    }
这意味着,只要将此变量更改为
false
,片段事务就可以自由执行。在保存活动状态时,此变量将变为
true
,即
onSaveInstanceState()


回到问题

您说过,以前您在提交来自
onActivityResult()
的事务时遇到问题。这意味着,以前
mStateSaved
没有被分配
false
,而现在是。事实上是这样的

以下是从O版本开始的实现:


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        mFragments.noteStateNotSaved();
        ...
    }
其中,将执行以下操作:


    public void noteStateNotSaved() {
        ...
        mStateSaved = false;
        ...
    }
相反,您可以看到Jelly Bean版本的实现:


    @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);
    }
任何内容都不会更改
mStateSaved
字段的值,如果提交事务,将引发异常

事实上,Kit Kat release中的行
MFFragments.noteStateNotSaved()
。正如您可以从Dianne Hackborn制作的中看到的:

ActivityFragment应清除状态保存时的标志 接收
onNewIntent()
。这可能发生在活动启动之前 恢复,所以我们可能还没有清除它。也需要这样做 在activityResult()上的
功能

总结

onActivityResult()
现在是否保证成为碎片事务的安全场所


假设你使用的是2012年10月制作的包括在内的资料来源——是的,这是一个碎片交易的安全场所。

看看@elmorabea,博客文章是我第一次发现这个问题时发现的资料之一。但是,正如阿齐兹比安下面的回答所示,它似乎不再是一个准确的解释n个安全窗口来提交碎片交易。阅读像这样的答案是一种纯粹的乐趣。谢谢你。谢谢,@Vasily,也很享受你的答案/谈话。@azizbekian当然我想回应其他评论,这是一个很好的答案,但我也想说,我没有立即接受+奖的唯一原因是我想等待看看是否还有其他人插话。谢谢你这么详细;非常感谢。@azizbekian感谢你这么深刻的解释。通过阅读代码,我假设
super.onActivityResult
应该是
onActivityResult
中的第一行,而不是最后一个原因。这是将
mStateSaved
设置为false的调用…我说的对吗?@ADM,除非你有具体的理由不把
super
call放在顶部,否则我看不出你为什么要把它放在底部。谢谢。