Fragment 事务

在运行时,FragmentManager 可以通过 Fragment 执行添加、移除、替换以及其他操作,以响应用户互动。您提交的每组 Fragment 更改称为一个“事务”,并且您可以使用 FragmentTransaction 类提供的 API 指定在事务内需执行何种操作。您可以将多个操作分组到一个事务中。例如,通过一个事务就可以添加或替换多个 Fragment。当您在同一个屏幕上显示多个同级 Fragment(例如使用分块视图)时,该分组会很实用。

您也可将每个事务保存到由 FragmentManager 管理的返回堆栈内,从而让用户能够回退 Fragment 更改(类似于回退 Activity)。

您可以通过调用 beginTransaction()FragmentManager 获取 FragmentTransaction 实例,如以下示例所示:

Kotlin

val fragmentManager = ...
val fragmentTransaction = fragmentManager.beginTransaction()

Java

FragmentManager fragmentManager = ...
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

每个 FragmentTransaction 上的最终调用必须提交事务。commit() 调用会向 FragmentManager 发出信号,指明所有操作均已添加到事务中。

Kotlin

val fragmentManager = ...
// The fragment-ktx module provides a commit block that automatically
// calls beginTransaction and commit for you.
fragmentManager.commit {
    // Add operations here
}

Java

FragmentManager fragmentManager = ...
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

// Add operations here

fragmentTransaction.commit();

允许对 Fragment 状态更改进行重新排序

每个 FragmentTransaction 都应使用 setReorderingAllowed(true)

Kotlin

supportFragmentManager.commit {
    ...
    setReorderingAllowed(true)
}

Java

FragmentManager fragmentManager = ...
fragmentManager.beginTransaction()
    ...
    .setReorderingAllowed(true)
    .commit();

对于行为兼容性,重新排序标志默认处于停用状态。但是,您必须允许 FragmentManager 正确执行 FragmentTransaction,尤其是它在返回堆栈上操作并运行动画和转换时。启用此标记可确保,如果多个事务一起执行,任何中间 Fragment(即添加然后立即被替换的 Fragment)不会经历生命周期改变,也不会执行动画或转换。请注意,此标志会影响事务的初始执行,也会影响使用 popBackStack() 对事务进行的逆转操作。

添加和移除 Fragment

如需将 Fragment 添加到 FragmentManager,请对事务调用 add()。此方法会收到用于存储此 Fragment 的容器的 ID,以及您要添加的 Fragment 的类名。添加的 Fragment 会转为 RESUMED 状态。强烈建议容器为 FragmentContainerView(视图层次结构的一部分)。

如需从宿主中移除 Fragment,请调用 remove(),同时传入通过 findFragmentById()findFragmentByTag() 从 Fragment 管理器检索到的 Fragment 实例。 如果 fragment 的视图之前已添加到容器中,此时系统会将该视图从容器中移除。移除的 fragment 会转为 DESTROYED 状态。

使用 replace() 将容器中现有的 Fragment 替换为您提供的新 Fragment 类的实例。调用 replace() 等同于对容器中的 Fragment 调用 remove() 后将新的 Fragment 添加到同一容器中。

以下代码段展示了如何将一个 Fragment 替换为另一个 Fragment:

Kotlin

// Create new fragment
val fragmentManager = // ...

// Create and commit a new transaction
fragmentManager.commit {
    setReorderingAllowed(true)
    // Replace whatever is in the fragment_container view with this fragment
    replace<ExampleFragment>(R.id.fragment_container)
}

Java

// Create new fragment and transaction
FragmentManager fragmentManager = ...
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setReorderingAllowed(true);

// Replace whatever is in the fragment_container view with this fragment
transaction.replace(R.id.fragment_container, ExampleFragment.class, null);

// Commit the transaction
transaction.commit();

在此示例中,ExampleFragment 的新实例将替换当前由 R.id.fragment_container 标识的布局容器中的 Fragment(如有)。

默认情况下,在 FragmentTransaction 中所做的更改不会添加到返回堆栈。如需保存这些更改,您可以对 FragmentTransaction 调用 addToBackStack()。如需了解详情,请参阅 Fragment 管理器

提交操作为异步操作

调用 commit() 不会立即执行事务,而是会将事务调度为能在主界面线程上运行就在主界面线程上运行。但是,您可以在必要时调用 commitNow() 以立即在您的界面线程上运行 Fragment 事务。

请注意,commitNowaddToBackStack 不兼容。或者,您也可以通过调用 executePendingTransactions() 执行由 commit() 调用提交的尚未运行的所有待处理 FragmentTransactions。这种处理方式与 addToBackStack 兼容。

对于绝大多数用例,只需 commit() 即可。

操作排序非常重要

FragmentTransaction 中执行操作的顺序至关重要,尤其是在使用 setCustomAnimations() 时。此方法将给定动画应用于遵守该方法的所有 Fragment 操作。

Kotlin

supportFragmentManager.commit {
    setCustomAnimations(enter1, exit1, popEnter1, popExit1)
    add<ExampleFragment>(R.id.container) // gets the first animations
    setCustomAnimations(enter2, exit2, popEnter2, popExit2)
    add<ExampleFragment>(R.id.container) // gets the second animations
}

Java

getSupportFragmentManager().beginTransaction()
        .setCustomAnimations(enter1, exit1, popEnter1, popExit1)
        .add(R.id.container, ExampleFragment.class, null) // gets the first animations
        .setCustomAnimations(enter2, exit2, popEnter2, popExit2)
        .add(R.id.container, ExampleFragment.class, null) // gets the second animations
        .commit()

限制 Fragment 的生命周期

FragmentTransactions 会影响在事务的作用域内添加的各个 Fragment 的生命周期状态。创建 FragmentTransaction 时,setMaxLifecycle() 会设置给定 Fragment 的最大生命周期状态。例如,ViewPager2 使用 setMaxLifecycle() 将屏幕外 Fragment 的最大生命周期状态限定为 STARTED 状态。

显示和隐藏 Fragment 的视图

分别使用 FragmentTransaction 方法 show()hide() 显示和隐藏已添加至容器的 Fragment 视图。这些方法可设置 Fragment 视图的可见性,而不会影响 Fragment 的生命周期。

虽然您无需使用 Fragment 事务切换 Fragment 中视图的可见性,但当需要对可见性状态进行更改从而与返回堆栈上的事务关联时,这些方法很有用。

附加和分离 Fragment

FragmentTransaction 方法 detach() 用于将 Fragment 与界面分离,从而销毁其视图层次结构。Fragment 所处状态 (STOPPED) 保持不变,与将其放入返回堆栈时的状态相同。这意味着 Fragment 已从界面中移除,但仍由 Fragment 管理器管理。

attach() 方法会重新附加之前分离的 Fragment。这会导致视图层次结构重新创建,附加到界面并显示。

由于 FragmentTransaction 被视为单个原子操作集,对同一事务中的同一 Fragment 实例同时调用 detachattach 可以有效地相互抵消,因此这可以避免销毁并立即重新创建 Fragment 界面。如需在分离后立即重新附加 Fragment,请使用单独的事务(如使用 commit(),则由 executePendingOperations() 分离)。