在片段活动中的commitAllowingStateLoss()函数

41

我的应用程序使用片段活动,只支持纵向模式并且无法旋转屏幕。

最初我使用的是commit()方法,但现在我计划将这些无差别更改为片段活动中的commitAllowingStateLoss()

是否有任何理由不重新评估我使用片段的每个个案而不是无差别地执行此操作?


你们支持3.0之前的版本吗? - Diogo Bento
5
有关此主题的更多信息,请查看我的博客文章。链接为:http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html - Alex Lockwood
2
一个非常好的问题。 - Subby
5个回答

57

如果我理解正确,您的意思是:无论何时使用一个片段,是否都没有重新评估每个单独的情况的原因呢?

答案是有的 - 您不应该在不仔细重新评估每个使用片段的情况下这样做。

当然,通过防止由于配置更改(屏幕旋转)而重新启动,您已经消除了其中一个关键问题领域:即用户在调用 onSaveInstanceState 之后但在 commitAllowingStateLoss 之前旋转屏幕。在这种情况下,片段或部分 UI 可能会丢失。有关此的非正式讨论,请参见此帖子

但在替换 commitcommitAllowingStateLoss 之前,还有其他情况需要考虑。

  1. 基本上,在 onSaveInstanceState 和 commitAllowingStateLoss 之间进行的任何 UI 更新:Android: IllegalStateException - When is it thrown?

  2. 如果您有任何 headless 片段来更新活动的 UI,则它们的某些更新可能会丢失(请参见此文章)。

  3. 安卓可能会“杀死”片段,因为手机/平板电脑资源不足(请参见此答案)。

当然,如果防止屏幕旋转,则可能不会调用 onSaveInstanceState,在这种情况下,更新丢失的机会增加了。

如果您决定使用`commitAllowingStateLoss`,那么有些事情可以做以最大程度地减小风险:例如,在父活动的下次重启时考虑执行`commit`/`executePendingTransactions`(我知道您不想这样做,但其他人可能会阅读这里)。
最后(再次提醒其他人阅读此处-这与您的情况无关),处理`IllegalStateException`可能有比从`commit`转移到`commitAllowStateLoss`更安全的方法。例如,您可以继续使用`commit`并处理`IllegalStateException`。或者,您可能遇到了Android中的一个错误,并且可能存在解决方法。

14
请查看我的博客文章,以获取更多信息。 - Alex Lockwood

6
public abstract int commit ()

调度提交此事务。提交将不会立即发生; 它将被安排在主线程上的工作中,以便在下一次该线程准备好时完成。

仅在其包含活动保存其状态之前,才能使用此方法提交事务。如果在此点之后尝试提交,则会引发异常。这是因为在提交后状态可能会丢失,如果需要从其状态恢复活动,则需要进行恢复。请参见 commitAllowingStateLoss(),了解在可能丢失提交的情况下应如何处理。

public abstract int commitAllowingStateLoss ()

自API level 11起添加

类似于commit(),但允许在保存活动状态后执行提交。这很危险,因为如果活动需要从其状态恢复,提交可能会丢失,因此只应用于对用户意外UI状态更改无关紧要的情况。

FragmentActivity限制

在Honeycomb(3.0)之前,活动状态在暂停之前被保存。片段是大量新状态,并且足够动态,以至于人们经常希望它们在暂停和停止之间发生变化。如果您尝试在保存片段状态后更改片段状态,则这些类将抛出异常,以避免意外丢失UI状态。但是,在Honeycomb之前过于严格,因为状态在暂停之前保存。为了解决这个问题,在运行平台早于Honeycomb时,如果您在状态保存和活动停止之间更改片段,则不会抛出异常。这意味着,在某些情况下,如果从其上次保存的状态恢复活动,则可能是用户最后看到的快照稍微之前的状态。

因此,如果您不关心状态丢失,我认为您的决定是可以的。 希望这能帮助您做出决策。


4
try {
    transaction.commit();
} catch (IllegalStateException e) {
}

1
如果commit()失败,当执行commitAllowingStateLoss()时,您可能会得到IllegalStateException: commit already called的错误提示... 因此这并不是一个真正的解决方案。 - GabrielOshiro
1
请注意,在执行 commitAllowingStateLoss() 方法之前,可能会导致状态丢失,请谨慎操作。 - Sreekanth Karumanaghat

3

1
您可以像这样覆盖next方法。
@Override
public void supportFinishAfterTransition() {
    finish();
    super.supportFinishAfterTransition();
}

它对我起作用了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接