在 onActivityResult() 中提交 FragmentTransaction 是否安全?
Is it safe to commit a FragmentTransaction inside onActivityResult()?
几年前,当我试图在我的 onActivityResult()
回调中提交 FragmentTransaction
时,我 运行 在我的一个应用程序中遇到了问题。谷歌搜索,我发现 this question and answer,上面写着
At the time that onActivityResult()
is called, the activity/fragment's state may not yet have been restored, and therefore any transactions that happen during this time will be lost as a result.
我最终为我的应用程序采用了同一答案中推荐的解决方案,生活很美好。然而,最近的实验表明情况可能发生了变化,现在 可能 从 onActivityResult()
.
内部提交 FragmentTransaction
是安全的
The documentation for (support v4) FragmentManager.beginTransaction()
将 t运行 操作的安全 window 定义为:
Note: A fragment transaction can only be created/committed prior to an activity saving its state. If you try to commit a transaction after FragmentActivity.onSaveInstanceState()
(and prior to a following FragmentActivity.onStart
or FragmentActivity.onResume()
, you will get an error.
正在阅读the documentation for onActivityResult()
,我明白了
You will receive this call immediately before onResume()
when your activity is re-starting.
这让我相信在 onActivityResult()
中执行这些 t运行 操作应该是安全的,因为 onStart()
已经被调用,将我置于安全 window.
我制作了一个应用程序来对此进行测试,并且我成功地看到了我在 onActivityResult()
中创建和提交的对话框片段。我有同一个应用程序还记录了 activity 生命周期回调,因此我可以检查它们的顺序,我每次都看到 onStart()
,然后是 onRestoreInstanceState()
,然后是 onActivityResult()
。
我错过了什么吗?还是框架发生了变化,onActivityResult()
现在 gua运行 将成为片段 t运行 操作的安全场所?此行为是否因 API 级别而异?
我发现 似乎以与我相同的方式阅读文档,但两者都超过一年了,而且都没有具体提到 onActivityResult()
作为 t[=58 的安全位置=]sactions.
深入了解资源
FragmentManager
class, called mStatedSaved
. This variable keeps track of the saved state depending on the activity's lifecycle callbacks. Here's 方法中有一个布尔变量,它会抛出众所周知的异常:
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
...
}
这意味着,一旦这个变量被更改为false
,那么片段交易就可以自由执行了。当保存 activity 的状态时,此变量将变为 true
,即 onSaveInstanceState()
.
回到问题
您说,您之前在从 onActivityResult()
提交事务时遇到问题。这应该意味着,以前 mStateSaved
没有被分配 false
而现在是。确实如此。
这是 O 版本的 onActivityResult()
实现:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mFragments.noteStateNotSaved();
...
}
其中,noteStateNotSaved()
会执行以下操作:
public void noteStateNotSaved() {
...
mStateSaved = false;
...
}
反之可以看到Jelly Bean发布onActivityResult()
的实现:
@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
字段的值,这会在提交事务时抛出异常。
事实上,Dianne Hackborn 的 mFragments.noteStateNotSaved()
was introduced in Kit-Kat release. As you can see by the commit's comment 行:
ActivityFragment should clear the flag that state is saved when it
receives onNewIntent()
. This can happen before the activity is
resumed, so we may not have cleared it yet. Also need to do the same
thing for onActivityResult()
.
总结
Is onActivityResult()
now guaranteed to be a safe place for fragment transactions?
假设您使用的来源包括 commit 4ccc001,它是在 2012 年 10 月制作的 - 是的,它是片段交易的安全场所。
几年前,当我试图在我的 onActivityResult()
回调中提交 FragmentTransaction
时,我 运行 在我的一个应用程序中遇到了问题。谷歌搜索,我发现 this question and answer,上面写着
At the time that
onActivityResult()
is called, the activity/fragment's state may not yet have been restored, and therefore any transactions that happen during this time will be lost as a result.
我最终为我的应用程序采用了同一答案中推荐的解决方案,生活很美好。然而,最近的实验表明情况可能发生了变化,现在 可能 从 onActivityResult()
.
FragmentTransaction
是安全的
The documentation for (support v4) FragmentManager.beginTransaction()
将 t运行 操作的安全 window 定义为:
Note: A fragment transaction can only be created/committed prior to an activity saving its state. If you try to commit a transaction after
FragmentActivity.onSaveInstanceState()
(and prior to a followingFragmentActivity.onStart
orFragmentActivity.onResume()
, you will get an error.
正在阅读the documentation for onActivityResult()
,我明白了
You will receive this call immediately before
onResume()
when your activity is re-starting.
这让我相信在 onActivityResult()
中执行这些 t运行 操作应该是安全的,因为 onStart()
已经被调用,将我置于安全 window.
我制作了一个应用程序来对此进行测试,并且我成功地看到了我在 onActivityResult()
中创建和提交的对话框片段。我有同一个应用程序还记录了 activity 生命周期回调,因此我可以检查它们的顺序,我每次都看到 onStart()
,然后是 onRestoreInstanceState()
,然后是 onActivityResult()
。
我错过了什么吗?还是框架发生了变化,onActivityResult()
现在 gua运行 将成为片段 t运行 操作的安全场所?此行为是否因 API 级别而异?
我发现 onActivityResult()
作为 t[=58 的安全位置=]sactions.
深入了解资源
FragmentManager
class, called mStatedSaved
. This variable keeps track of the saved state depending on the activity's lifecycle callbacks. Here's 方法中有一个布尔变量,它会抛出众所周知的异常:
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
...
}
这意味着,一旦这个变量被更改为false
,那么片段交易就可以自由执行了。当保存 activity 的状态时,此变量将变为 true
,即 onSaveInstanceState()
.
回到问题
您说,您之前在从 onActivityResult()
提交事务时遇到问题。这应该意味着,以前 mStateSaved
没有被分配 false
而现在是。确实如此。
这是 O 版本的 onActivityResult()
实现:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mFragments.noteStateNotSaved();
...
}
其中,noteStateNotSaved()
会执行以下操作:
public void noteStateNotSaved() {
...
mStateSaved = false;
...
}
反之可以看到Jelly Bean发布onActivityResult()
的实现:
@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
字段的值,这会在提交事务时抛出异常。
事实上,Dianne Hackborn 的 mFragments.noteStateNotSaved()
was introduced in Kit-Kat release. As you can see by the commit's comment 行:
ActivityFragment should clear the flag that state is saved when it receives
onNewIntent()
. This can happen before the activity is resumed, so we may not have cleared it yet. Also need to do the same thing foronActivityResult()
.
总结
Is
onActivityResult()
now guaranteed to be a safe place for fragment transactions?
假设您使用的来源包括 commit 4ccc001,它是在 2012 年 10 月制作的 - 是的,它是片段交易的安全场所。