Fragment 基础与加载方式

1. Fragment 是什么

Fragment 是 Android 中用于构建可复用 UI 模块的组件。它通常表示一个界面片段,拥有自己的布局、生命周期和输入事件处理能力,但它不能独立存在,必须依附于 Activity 或另一个 Fragment

更准确的理解是:

Activity = 宿主与页面级容器
Fragment = 页面中的可复用 UI 与逻辑单元
View = 更底层的 UI 绘制与交互单元

Fragment 适合用在:

  • 一个 Activity 中切换多个页面区域,例如首页 Tab。
  • 适配平板、折叠屏、横竖屏布局。
  • 把复杂页面拆成多个独立模块。
  • 和 Navigation Component 配合管理页面栈。

2. Fragment 是“第五大组件”吗?

面试中经常有人说 Fragment 是 Android 的“第五大组件”,这个说法可以作为民间记忆法,但不是官方组件分类。

Android 传统四大组件是:

组件 是否需要在 Manifest 中声明 是否可以独立被系统调度 典型职责
Activity 展示界面
Service 后台或前台任务
BroadcastReceiver 是/动态注册 接收广播
ContentProvider 跨进程数据共享
Fragment Activity 内的 UI 模块

所以更严谨的回答是:

Fragment 有生命周期,使用频率很高,可以灵活嵌入 Activity,但它不是与四大组件同级的系统组件,而是依附于宿主的 UI 模块。

3. 使用 AndroidX Fragment

现代项目应使用 AndroidX 版本:

import androidx.fragment.app.Fragment

不要再使用平台版本:

// 不推荐:android.app.Fragment 已废弃
import android.app.Fragment

依赖示例:

implementation("androidx.fragment:fragment-ktx:<latest-version>")

4. Fragment 的加载方式

Fragment 加载到宿主中,主要有两类方式:XML 声明和代码动态添加。

4.1 XML 静态声明:推荐 FragmentContainerView

旧资料中常见 <fragment> 标签:

<fragment
    android:id="@+id/my_fragment"
    android:name="com.example.MyFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

现在更推荐使用 FragmentContainerView,因为它更符合 FragmentManager 的状态管理规则:

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/fragment_container"
    android:name="com.example.HomeFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

适合场景:页面固定只有一个 Fragment,不需要复杂切换。

4.2 动态加载:FragmentManager + FragmentTransaction

动态加载更常见,适合运行时切换页面:

supportFragmentManager.commit {
    replace(R.id.fragment_container, HomeFragment())
}

如果没有使用 KTX,也可以写成:

val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, HomeFragment())
transaction.commit()

常见操作:

方法 作用 是否销毁原 Fragment 视图
add() 添加 Fragment
remove() 移除 Fragment
replace() 替换容器中的 Fragment 通常会移除旧 Fragment
hide() / show() 隐藏或显示已添加 Fragment 的 View
detach() / attach() 分离或重新附加 Fragment 的 View detach 会销毁 View

5. Fragment 与 ViewPager / ViewPager2

旧资料中常见:

  • FragmentPagerAdapter:页面少时使用。
  • FragmentStatePagerAdapter:页面多时使用。

这个结论在老项目中仍能看懂,但新项目应该改为:

ViewPager 已被 ViewPager2 替代
FragmentPagerAdapter / FragmentStatePagerAdapter 已废弃
ViewPager2 + FragmentStateAdapter 是当前推荐组合

示例:

class HomePagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {
    override fun getItemCount(): Int = 3

    override fun createFragment(position: Int): Fragment {
        return when (position) {
            0 -> HomeFragment()
            1 -> MessageFragment()
            else -> MineFragment()
        }
    }
}

配合 TabLayout:

viewPager.adapter = HomePagerAdapter(this)

TabLayoutMediator(tabLayout, viewPager) { tab, position ->
    tab.text = when (position) {
        0 -> "首页"
        1 -> "消息"
        else -> "我的"
    }
}.attach()

6. 面试回答模板

问题:Fragment 为什么常被称为第五大组件?

可以这样回答:

这个说法不是官方分类。Fragment 不能独立运行,必须依附 Activity 或父 Fragment,所以它不是和四大组件同级的系统组件。但 Fragment 有自己的生命周期、布局和事件处理能力,使用频率非常高,常用于页面模块化、Tab 切换、平板和折叠屏适配,因此面试中有人把它称为第五大组件。

问题:Fragment 如何加载到 Activity 中?

可以这样回答:

主要有 XML 静态声明和代码动态添加两种。老写法用 <fragment>,新项目更推荐 FragmentContainerView。动态加载通过 FragmentManager 开启 FragmentTransaction,使用 addreplaceshowhidedetachattach 等方法提交事务。如果是页面导航,推荐优先考虑 Jetpack Navigation。