首页 / Android 入门教程 / Fragment 事务

Android 入门教程

Fragment 事务

本教程共 100 篇 · 第 40 篇 · 更新于 2026-07-28 · 约 8 分钟阅读

AndroidAndroid 入门教程FragmentFragment事务返回栈addToBackStack

40. Fragment 事务

本节目标:掌握 Fragment 事务的各种操作(add/replace/remove/hide/show),学会用返回栈实现「返回上一个 Fragment」,能给切换加动画,避免常见的事务坑。

事务是什么

打个比方:事务就像银行转账—你要么全部成功,要么全部不干。Fragment 事务把一组界面变更打包成一个原子操作:添加、替换、移除这些动作要么一起生效,要么一起撤销。

对 Fragment 的所有修改都要通过事务来完成。用 FragmentManager 开启事务,执行操作,最后提交。

基本操作

开启事务

supportFragmentManager.commit {
    // 在这里做各种 Fragment 操作
}

这是 KTX 简化写法,等价于:

val transaction = supportFragmentManager.beginTransaction()
// 操作...
transaction.commit()

replace:替换

最常用的操作,把容器里的 Fragment 换成新的:

supportFragmentManager.commit {
    replace(R.id.fragment_container, DetailFragment())
    addToBackStack(null) // 加到返回栈,按返回键能退回上一个
}
Warning
  • replace() 会先移除容器里现有的 Fragment,再添加新的。被替换的 Fragment 如果没加到返回栈,会被销毁(onDestroyView -> onDestroy -> onDetach)。如果加了返回栈,只会走到 onDestroyView,Fragment 实例保留,返回时重建视图。

add:添加

add() 是往容器里加一个 Fragment,不移除已有的:

supportFragmentManager.commit {
    add(R.id.fragment_container, HomeFragment(), "home_tag")
}

第三个参数是 Tag,之后可以用 findFragmentByTag("home_tag") 找到它。

remove:移除

val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
if (fragment != null) {
    supportFragmentManager.commit {
        remove(fragment)
    }
}

hide / show:隐藏和显示

hide()show() 不销毁 Fragment 的视图,只是设为不可见/可见。适合在底部导航栏切换 Tab 时用,避免每次切换都重建:

supportFragmentManager.commit {
    hide(currentFragment)
    show(targetFragment)
}
Tip
  • 底部导航栏推荐用 hide() / show() 而不是 replace()replace 每次都销毁重建,浪费时间、丢失滚动位置;hide/show 只切可见性,体验更流畅。但要预加载所有 Fragment,内存占用稍高。

返回栈

默认情况下,Fragment 切换后按返回键会直接退出 Activity。加到返回栈后,按返回键会回退到上一个 Fragment。

supportFragmentManager.commit {
    replace(R.id.fragment_container, DetailFragment())
    addToBackStack(null) // 参数是事务的名称,可用于 popBackStack(name)
}

手动出栈

// 回退一步
supportFragmentManager.popBackStack()

// 回退到指定名称的事务
supportFragmentManager.popBackStack("transaction_name", 0)

// 回退到某个事务的状态(包含该事务)
supportFragmentManager.popBackStack(
    "transaction_name",
    FragmentManager.POP_BACK_STACK_INCLUSIVE
)

监听返回栈变化

supportFragmentManager.addOnBackStackChangedListener {
    // 返回栈发生变化时回调
    updateActionBar()
}
Note
  • Android 13+ 引入了预测式返回手势。如果你用了返回栈,建议配合 OnBackPressedDispatcher 处理返回逻辑,而不是老式的 onBackPressed()

事务动画

给 Fragment 切换加动画,提升体验。

方式一:标准动画资源

res/anim/ 下定义动画文件,比如 fade_in.xml

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="0.0"
    android:toAlpha="1.0"
    android:duration="300" />

事务里设置:

supportFragmentManager.commit {
    setCustomAnimations(
        R.anim.fade_in,   // 新 Fragment 进入
        R.anim.fade_out,  // 旧 Fragment 退出
        R.anim.fade_in,   // 返回栈弹出时新 Fragment 进入
        R.anim.fade_out   // 返回栈弹出时旧 Fragment 退出
    )
    replace(R.id.fragment_container, DetailFragment())
    addToBackStack(null)
}

方式二:过渡动画(Transition)

API 21+ 支持用 Transition API 做更丰富的动画:

// 在 Fragment 里设置
class DetailFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 进入时淡入
        enterTransition = Fade()
        // 退出时淡出
        exitTransition = Fade()
    }
}
Tip
  • 用 Transition API 可以做出共享元素过渡效果(一个元素从列表页飞到详情页),体验很好。不过设置稍复杂,需要给共享视图加 transitionName

commit vs commitNow

提交事务有两种方式:

  • commit():异步提交,加到主线程消息队列,不立即执行。
  • commitNow():同步提交,立即执行完所有操作。
// 异步,常用
supportFragmentManager.commit { ... }

// 同步,立即生效
supportFragmentManager.commitNow { ... }
Warning
  • commit() 在 Activity 保存状态之后(onSaveInstanceState 之后)调用会崩溃。如果你必须在状态保存后提交,用 commitAllowingStateLoss(),但要接受可能丢失状态的风险。
方法执行时机能在 onSaveInstanceState 后调用
commit()异步否(崩溃)
commitNow()同步否(崩溃)
commitAllowingStateLoss()异步

常见坑

坑一:重复添加

如果 Fragment 已经在容器里,又 add 一次会报错。先检查:

if (supportFragmentManager.findFragmentById(R.id.fragment_container) == null) {
    supportFragmentManager.commit {
        replace(R.id.fragment_container, HomeFragment())
    }
}

坑二:在 onResume 之前操作 Fragment

Fragment 事务在 onResume() 之前提交可能有问题,特别是涉及返回栈的操作。如果需要在 Fragment 创建后立即做后续操作,用 postponeEnterTransition() + startPostponedEnterTransition() 延迟过渡。

坑三:状态丢失

在后台时(onStop 之后)执行 commit() 会崩溃。用 commitAllowingStateLoss() 替代,或者把操作延迟到 onResume()

小结

Fragment 事务是修改界面的原子操作,replace 最常用,hide/show 适合 Tab 切换。返回栈让用户能回退,动画让切换更流畅。记住 commit 是异步的、状态保存后要用 commitAllowingStateLoss。下一节我们看 Fragment 之间怎么传数据。