[Android 从零到一] Fragment 基础与生命周期

Fragment 基础与生命周期

一、背景

Android 从 API 11(Android 3.0)引入了 Fragment,最初是为了在大屏平板上实现灵活的 UI 布局。如今它已成为 Android 开发的核心组件,即使是手机上的单屏 App 也广泛使用 Fragment 来管理界面。

简单来说,Fragment 是一种可以嵌入到 Activity 中的 UI 片段,它有自己的布局、生命周期和事件处理能力。

二、核心概念

2.1 什么是 Fragment?

Fragment 是 Activity 中 UI 的一个行为部分。可以理解为"子 Activity"——它有自己的布局和生命周期,但必须依赖于 Activity 才能存在。

2.2 Fragment 的生命周期

Fragment 有 7 个核心生命周期回调,与 Activity 紧密关联:

  • onAttach() — Fragment 被关联到 Activity
  • onCreate() — 初始化 Fragment(非 UI 相关)
  • onCreateView() — 加载布局文件
  • onViewCreated() — 视图创建完毕,初始化 UI 控件
  • onStart() — Fragment 可见
  • onResume() — Fragment 可与用户交互
  • onPause() — Fragment 部分不可见
  • onStop() — Fragment 完全不可见
  • onDestroyView() — 视图被销毁
  • onDestroy() — Fragment 销毁
  • onDetach() — 与 Activity 解除关联

2.3 生命周期联动

当宿主 Activity 经历其生命周期时,Fragment 也会跟随变化。一个关键点是 onCreateViewonDestroyView 成对出现——每次 Fragment 离开屏幕时视图会被销毁,但 Fragment 实例可能仍然存活(比如被回退栈保留)。

三、代码实战(Kotlin)

3.1 定义 Fragment

class MyFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // 加载布局文件
        return inflater.inflate(R.layout.fragment_my, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 初始化 UI,findViewById 已弃用,用 View Binding
        val tvTitle = view.findViewById<TextView>(R.id.tv_title)
        tvTitle.text = "Hello Fragment"
    }
}

3.2 布局文件

<!-- fragment_my.xml -->
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="默认标题"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_margin="16dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

3.3 在 Activity 中添加 Fragment

方法一:静态添加(在布局中声明)

<!-- activity_main.xml -->
<androidx.fragment.app.FragmentContainerView
    android:id="@+id/fragment_container"
    android:name="com.example.app.MyFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

方法二:动态添加(Kotlin 代码)

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        if (savedInstanceState == null) {
            // 动态添加 Fragment
            supportFragmentManager.commit {
                replace(R.id.fragment_container, MyFragment())
                addToBackStack(null) // 添加到回退栈
            }
        }
    }
}

3.4 Fragment 与 Activity 通信

// Fragment 定义接口
class ListFragment : Fragment() {

    interface OnItemSelectedListener {
        fun onItemSelected(itemId: Int)
    }

    private var listener: OnItemSelectedListener? = null

    override fun onAttach(context: Context) {
        super.onAttach(context)
        // 确保 Activity 实现了接口
        listener = context as? OnItemSelectedListener
    }

    override fun onDetach() {
        super.onDetach()
        listener = null
    }

    fun onItemClicked(id: Int) {
        listener?.onItemSelected(id)
    }
}

// Activity 实现接口
class MainActivity : AppCompatActivity(), ListFragment.OnItemSelectedListener {

    override fun onItemSelected(itemId: Int) {
        // 切换到详情 Fragment
        supportFragmentManager.commit {
            replace(R.id.detail_container, DetailFragment.newInstance(itemId))
            addToBackStack("detail")
        }
    }
}

四、避坑指南

  • Fragment 重叠问题:Activity 重建时系统会恢复 Fragment,如果在 onCreate 中再次 commit 会导致重叠。解决办法:加上 savedInstanceState == null 判断。
  • FragmentManager 的生命周期:不要在 Activity 的 onSaveInstanceState 之后 commit 事务,会抛 IllegalStateException。可以用 commitAllowingStateLoss() 但需谨慎。
  • 空构造函数要求:Fragment 必须有一个公开的无参构造函数,系统在重建时会通过反射调用它。不要用带参数的构造器,用 newInstance() 静态方法 + Bundle 传参。
  • View Binding 与 Fragment:在 onCreateView 中 inflate 布局,在 onDestroyView 中置空 binding 引用防止内存泄漏。

五、总结

Fragment 是 Android 开发的基础组件,掌握它的生命周期和通信机制至关重要。核心要点:

  • 生命周期与 Activity 联动,但有自己的 onCreateView/onDestroyView 过程
  • 动态添加比静态声明更灵活,搭配 addToBackStack 实现导航
  • Fragment 与 Activity 通信通过接口回调,避免直接持有 Activity 引用
  • 使用 FragmentContainerView 替代旧的 <fragment> 标签

下一期预告:RecyclerView 入门,敬请期待

posted @ 2026-06-10 11:14  天总会晴的  阅读(0)  评论(0)    收藏  举报