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放在顶部,否则我看不出你为什么要把它放在底部。谢谢。