新的FragmentTransaction commitNow()如何在内部工作?

时间:2016-07-25 11:32:19

标签: android fragmenttransaction

Android N和支持库版本24中添加的新commitNow()方法包含有限且有点令人困惑的文档。

  

同步提交此事务。任何添加的片段都将是   初始化并完全进入他们的生命周期状态   主机和任何删除的碎片将在之前相应地拆除   这个电话会回来。以这种方式提交事务允许   片段作为专用的封装组件添加   监控主机的生命周期状态,同时提供更坚固的功能   这些片段完全初始化时的排序保证   准备好了。管理视图的片段将创建这些视图   并附上。

     

调用commitNow比调用commit()更可取   其次是FragmentManager.executePendingTransactions()作为后者   会有尝试提交所有当前的副作用   待处理的交易是否是所需的行为。

     

以这种方式提交的交易可能无法添加到   FragmentManager的后台堆栈,因为这样做会破坏其他预期的   为其他异步提交的事务排序保证。   如果事务,此方法将抛出IllegalStateException   之前请求将其添加到后台堆栈中   addToBackStack(字符串)即可。

     

只能使用此提交事务   在其包含活动之前保存其状态的方法。如果   在该点之后尝试提交,将抛出异常。   这是因为如果活动,提交后的状态可能会丢失   需要从其州恢复。请参阅commitAllowingStateLoss()   可能会失去提交的情况。

我用粗体突出显示了我认为令人困惑的部分。

所以,我的主要关注点/问题是:

1 - 他们可能不会被添加?它说我会得到一个IllegalStateException,它会被添加还是不被添加?

2 - 如果我们想在backstack中添加片段,我接受这样的事实:我不能使用它。它没有说的是你得到了这个例外:

java.lang.IllegalStateException: This transaction is already being added to the back stack

!!!! ????

所以我不能自己打电话给addToBackStack(String),因为它在内部为我打电话?对不起但是......什么?为什么?如果我不希望它被添加到后台堆中怎么办?如果我稍后尝试从后台堆栈中使用该片段但是因为它可能不会被添加,以后它不存在呢?

如果我使用commitAllowingStateLoss(),看起来这是预期的事情,但我发现commitNowAllowingStateLoss()也存在,所以......它遵循什么样的逻辑?

TL; DR

commitNow()内部如何处理backstack?

2 个答案:

答案 0 :(得分:72)

当我们遇到像这样的问题时,Android源代码是开源的,这是一件好事!

答案

那么让我们来看看BackStackRecord源here

@Override
public void commitNow() {
    disallowAddToBackStack();
    mManager.execSingleAction(this, false);
}

@Override
public FragmentTransaction disallowAddToBackStack() {
    if (mAddToBackStack) {
        throw new IllegalStateException(
                "This transaction is already being added to the back stack");
    }
    mAllowAddToBackStack = false;
    return this;
}

如果您在交易中致电mAddToBackStackaddToBackStack将设置为true。

因此,为了回答您的问题,当您致电addToBackStack时,内部不会调用commitNow(),这是异常消息。我认为它应该说You're not allowed to add to backstack when using commitNow()而不是当前的消息。

加成:

如果我们深入研究FragmentManager源代码herecommitNow()实际上与上面所写的executePendingTransactions() 几乎相同,而是执行之前提交的所有内容transaction,commitNow()只会提交该事务。

我认为这是commitNow()不允许添加到backstack的主要原因,因为它不能保证没有任何其他挂起的事务。如果commitNow()可以添加到backstack,我们可能会破坏我们的后端序列,这将导致意外的事情。

答案 1 :(得分:7)

长话短说

如果您将addToBackStack()Fragment一起使用,请使用commitNow(),而使用commit()

FragmentaddToBackStack()commitNow()一起使用会导致片段事务顺序不一致,因此必须使用commit()

有关详细说明,请查看此article