「精华」Fragment 从入门到实战:阿里大佬带你彻底搞懂 Android 模块化开发!
目录
1. 概述
什么是 Fragment?
Fragment(碎片)是 Android 的模块化 UI 组件,它没有自己的窗口,必须依附在 Activity 上才能显示。
Activity(独立窗口)
│
└── Fragment(寄生在 Activity 窗口中)
├── Fragment A
├── Fragment B
└── Fragment C
为什么需要 Fragment?
- 模块化:把复杂界面拆分成多个独立模块
- 复用:同一个 Fragment 可在多个 Activity 中使用
- 适配:平板/手机使用不同 Fragment 组合
- 生命周期:跟 Activity 绑定,Activity 不可见时 Fragment 也不可见
2. Fragment vs Activity
| 对比 | Activity | Fragment |
|---|---|---|
| 窗口 | 有独立窗口 | 没有窗口,寄生在 Activity |
| 生命周期 | 系统控制 | 依赖 Activity |
| 创建方式 | 直接 startActivity() | 通过 FragmentManager 添加 |
| 栈管理 | 系统自动管理 | 需手动 addToBackStack() |
| 独立运行 | 可以独立运行 | 必须依附 Activity |
简单理解:
- Activity = 页面
- Fragment = 页面里的模块
3. 基本使用步骤
3.1 创建 Fragment 类
class LeftFragment : Fragment() {
private var btnShowImage: Button? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// 加载布局
return inflater.inflate(R.layout.fragment_left, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 绑定控件(在视图创建完成后)
btnShowImage = view.findViewById(R.id.btnShowImage)
btnShowImage?.setOnClickListener {
// 处理点击
}
}
}
3.2 创建 Fragment 布局
<!-- res/layout/fragment_left.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#E3F2FD">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="左侧 Fragment" />
<Button
android:id="@+id/btnShowImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="显示图片" />
</LinearLayout>
3.3 在 Activity 中添加 Fragment
方式一:XML 静态添加
<!-- activity_main.xml -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:name="com.example.app.LeftFragment"
android:id="@+id/leftFragment"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
</LinearLayout>
方式二:代码动态添加(推荐)
class MainActivity : AppCompatActivity() {
private lateinit var leftFragment: LeftFragment
private lateinit var rightFragment: RightFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 创建 Fragment 实例
leftFragment = LeftFragment()
rightFragment = RightFragment()
// 添加到容器
supportFragmentManager.beginTransaction().apply {
replace(R.id.leftContainer, leftFragment, "left_fragment")
replace(R.id.rightContainer, rightFragment, "right_fragment")
commit()
}
}
}
4. Fragment 事务
4.1 为什么叫"事务"?
借鉴数据库事务概念——多个操作打包成一组,commit 后一起生效。
supportFragmentManager.beginTransaction()
.hide(fragmentA)
.show(fragmentB)
.add(fragmentC)
.remove(fragmentD)
.commit() // 一次性提交所有操作
4.2 常用方法
| 方法 | 作用 |
|---|---|
add() | 添加 Fragment |
remove() | 移除 Fragment |
replace() | 替换 Fragment |
hide() | 隐藏 Fragment(不销毁) |
show() | 显示已隐藏的 Fragment |
addToBackStack() | 添加到返回栈 |
4.3 提交方式
// 异步提交(常用)
transaction.commit()
// 立即执行(在主线程)
transaction.commitNow()
// 允许状态丢失时提交(少用)
transaction.commitAllowingStateLoss()
5. Fragment 与 Activity 通信
5.1 Fragment → Activity
// Fragment 中调用
(activity as? MyActivity)?.doSomething()
// 推荐:先判断 null
(activity as? MyActivity)?.let { activity ->
activity.showData(data)
}
5.2 Activity → Fragment
// Activity 中获取 Fragment 并调用其方法
val fragment = supportFragmentManager.findFragmentByTag("right_fragment") as? RightFragment
fragment?.showImage()
5.3 Fragment → Fragment
通过 Activity 作为中转:
// LeftFragment 中
(activity as? FragmentTestActivity)?.showImage()
// FragmentTestActivity 中
fun showImage() {
rightFragment.showImage()
}
// RightFragment 中
fun showImage() {
// 显示图片视图
}
6. Fragment 返回栈
6.1 问题
Activity 有系统管理的栈,但 Fragment 默认没有。
没有返回栈:
replace(A, B) → replace(B, C)
按 Back → 没有任何反应
有返回栈:
replace(A, B).addToBackStack(null)
replace(B, C).addToBackStack(null)
按 Back → 恢复 B
再按 Back → 恢复 A
6.2 使用方法
supportFragmentManager.beginTransaction()
.replace(R.id.container, FragmentB)
.addToBackStack(null) // 添加到返回栈
.commit()
6.3 监听返回键
// 在 Activity 中监听
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount > 0) {
supportFragmentManager.popBackStack()
} else {
super.onBackPressed()
}
}
// 推荐:使用 OnBackPressedCallback
onBackPressedDispatcher.addCallback(this) {
if (supportFragmentManager.backStackEntryCount > 0) {
supportFragmentManager.popBackStack()
true // 消费了返回键
} else {
false // 传递给系统处理
}
}
7. 实战:双 Fragment 布局
7.1 布局文件
<!-- activity_fragment_test.xml -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="3">
<FrameLayout
android:id="@+id/leftContainer"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#BDBDBD" />
<FrameLayout
android:id="@+id/rightContainer"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="match_parent" />
</LinearLayout>
7.2 Host Activity
class FragmentTestActivity : AppCompatActivity() {
private lateinit var leftFragment: LeftFragment
private lateinit var rightFragment: RightFragment
companion object {
const val TAG_LEFT = "left_fragment"
const val TAG_RIGHT = "right_fragment"
fun actionStart(context: Context) {
context.startActivity(Intent(context, FragmentTestActivity::class.java))
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_fragment_test)
setupFragments()
}
private fun setupFragments() {
leftFragment = LeftFragment()
rightFragment = RightFragment()
supportFragmentManager.beginTransaction().apply {
replace(R.id.leftContainer, leftFragment, TAG_LEFT)
replace(R.id.rightContainer, rightFragment, TAG_RIGHT)
commit()
}
}
// 暴露给 LeftFragment 调用
fun showImage() = rightFragment.showImage()
fun showText() = rightFragment.showText()
fun showList() = rightFragment.showList()
}
7.3 LeftFragment
class LeftFragment : Fragment() {
private var btnShowImage: Button? = null
private var btnShowText: Button? = null
private var btnShowList: Button? = null
override fun onCreateView(...): View? {
return inflater.inflate(R.layout.fragment_left, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btnShowImage = view.findViewById(R.id.btnShowImage)
btnShowText = view.findViewById(R.id.btnShowText)
btnShowList = view.findViewById(R.id.btnShowList)
btnShowImage?.setOnClickListener {
(activity as? FragmentTestActivity)?.showImage()
}
btnShowText?.setOnClickListener {
(activity as? FragmentTestActivity)?.showText()
}
btnShowList?.setOnClickListener {
(activity as? FragmentTestActivity)?.showList()
}
}
}
总结
- Fragment 是寄生组件,没有独立窗口,必须依附 Activity
- 通过 FragmentManager 管理,使用事务进行添加/替换/删除
- 通信通过 Activity 中转,Fragment 之间不直接通信
- 返回栈需要手动管理,使用
addToBackStack()添加 - 生命周期跟 Activity 绑定,但有自己独特的方法(onCreateView、onViewCreated 等)
1119

被折叠的 条评论
为什么被折叠?



