多年前,当我尝试在FragmentTransaction
回调中提交onActivityResult()
时,我在其中一个应用中遇到了问题。谷歌搜索,我发现this question and answer,说
在调用
onActivityResult()
时,活动/片段的状态可能尚未恢复,因此在此期间发生的任何事务都将因此而丢失。
我完全适应了我的应用程序在相同答案中推荐的解决方案,生活很美好。但是,最近的实验表明,事情可能已经发生了变化,现在可能可以安全地从FragmentTransaction
内部提交onActivityResult()
。
The documentation for (support v4) FragmentManager.beginTransaction()
将交易的安全窗口定义为:
注意:片段事务只能在活动保存其状态之前创建/提交。如果您尝试在
FragmentActivity.onSaveInstanceState()
之后(以及之后的FragmentActivity.onStart
或FragmentActivity.onResume()
之前提交交易,则会收到错误。
阅读the documentation for onActivityResult()
,我看到了
当您的活动重新开始时,您会在
onResume()
之前立即收到此来电。
这让我相信在onActivityResult()
执行这些交易应该是安全的,因为onStart()
已经被调用,让我进入安全窗口。
我制作了一个应用程序来测试它,并且我成功地看到了我在onActivityResult()
内创建和提交的对话框片段。我有相同的应用程序也记录活动生命周期回调,所以我可以检查他们的订单,我看到onStart()
,然后onRestoreInstanceState()
,然后每次onActivityResult()
。
我错过了什么吗?或者框架已更改,onActivityResult()
现在保证是片段交易的安全位置?此行为是否因API级别而异?
我发现another question and answer似乎以与我相同的方式阅读文档,但两者都超过一年,并且没有特别指onActivityResult()
作为交易的安全场所。
答案 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的来源 - 是的,这是片段交易的安全场所。