Android 碎片(Fragment)(建议收藏)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目:《Spring AI 项目实战》 正在持续爆肝中,基于 Spring AI + Spring Boot 3.x + JDK 21..., 点击查看 ;
- 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
在 Android 开发中,Android 碎片(Fragment) 是一个核心概念,它允许开发者将复杂的 UI 结构拆分成独立的模块,从而实现更灵活的界面设计和代码复用。对于初学者来说,理解 Fragment 的工作原理和应用场景是迈向高级开发的重要一步。本文将从基础概念讲起,逐步深入其生命周期、交互逻辑以及实际应用案例,帮助读者掌握这一强大工具。
什么是 Fragment?
Fragment 是 Android 中一种可重用的 UI 组件,它可以嵌入到 Activity 中,类似于一个“子窗口”。通过 Fragment,开发者可以将复杂的界面拆分成多个独立的模块,每个模块负责不同的功能或视图。例如,一个新闻应用的主界面可能包含“列表 Fragment”和“详情 Fragment”,前者展示文章标题,后者显示文章内容。
Fragment 的核心优势在于:
- 模块化设计:将界面拆分后,代码更清晰,维护更方便。
- 响应式布局:根据屏幕尺寸或设备类型动态调整 Fragment 的排列方式(如平板与手机的布局差异)。
- 代码复用:同一 Fragment 可以在多个 Activity 中复用,减少重复开发。
比喻:
将 Activity 想象为一间房间,而 Fragment 就是房间内的不同功能区(如客厅、卧室)。你可以根据需求调整功能区的位置或数量,甚至将多个房间的功能区组合在一起。
Fragment 的生命周期与 Activity 的关系
Fragment 的生命周期与 Activity 密切相关,但两者并不完全同步。以下是关键回调方法及其作用:
1. onCreate()
- 作用:初始化 Fragment 的数据和配置。
- 与 Activity 的关系:当 Activity 的
onCreate()
执行时,Fragment 的onCreate()
会被触发。
2. onCreateView()
- 作用:加载 Fragment 的布局文件(如 XML 文件)。
- 返回值:必须返回一个
View
对象,即 Fragment 的根视图。
3. onStart() 和 onResume()
- 作用:分别表示 Fragment 开始可见和获得用户交互权限。
4. onStop() 和 onDestroy()
- 作用:表示 Fragment 停止或被销毁。
关键区别:
当 Activity 被暂停时,其内的所有 Fragment 也会暂停;但当 Activity 销毁时,Fragment 可能会被重新创建(如屏幕旋转)。
如何创建和管理 Fragment?
步骤 1:创建 Fragment 类
继承 Fragment
类,并重写 onCreateView()
方法加载布局:
class MyFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_my, container, false)
}
}
步骤 2:在 Activity 中添加 Fragment
方法 1:通过 XML 布局嵌入
在 Activity 的布局文件中定义 Fragment 的容器:
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
然后在代码中绑定 Fragment:
supportFragmentManager.beginTransaction()
.add(R.id.fragment_container, MyFragment())
.commit()
方法 2:动态替换 Fragment
通过 replace()
方法切换不同 Fragment:
val newFragment = DetailFragment()
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, newFragment)
.addToBackStack(null) // 添加到返回栈
.commit()
Fragment 之间的通信与数据传递
方案 1:通过 Activity 中转
当两个 Fragment 需要交互时,可以通过共同的 Activity 作为“中间人”。例如,列表 Fragment 点击事件触发后,通知 Activity,再由 Activity 通知详情 Fragment 更新内容:
// 在 Activity 中定义接口
interface OnItemSelectedListener {
fun onItemSelected(item: String)
}
// 列表 Fragment 实现点击监听
class ListFragment : Fragment() {
private lateinit var listener: OnItemSelectedListener
override fun onAttach(context: Context) {
super.onAttach(context)
listener = context as OnItemSelectedListener
}
// 传递数据
private fun onItemClick(item: String) {
listener.onItemSelected(item)
}
}
方案 2:使用 ViewModel 共享数据
对于复杂场景,可以借助 ViewModel
实现跨 Fragment 数据共享:
// 定义共享 ViewModel
class SharedViewModel : ViewModel() {
val selectedItem = MutableLiveData<String>()
}
// Fragment A 设置数据
viewModel.selectedItem.value = "Item 1"
// Fragment B 观察数据
viewModel.selectedItem.observe(viewLifecycleOwner) { item ->
// 更新 UI
}
进阶技巧:嵌套 Fragment 与 Back Stack 管理
1. 嵌套 Fragment
Fragment 可以包含其他 Fragment,例如在一个主 Fragment 中动态加载子 Fragment。这通过 getChildFragmentManager()
实现:
// 在父 Fragment 中添加子 Fragment
childFragmentManager.beginTransaction()
.add(R.id.child_container, ChildFragment())
.commit()
2. 管理 Back Stack
通过 addToBackStack()
方法,可以记录 Fragment 事务的“历史记录”,支持用户通过返回键返回上一个界面:
supportFragmentManager.beginTransaction()
.replace(R.id.container, newFragment)
.addToBackStack("detail")
.commit()
实际案例:实现一个动态界面
场景描述
设计一个新闻应用,主界面包含左右两栏:左边是文章列表,右边是文章详情。当屏幕宽度不足时,切换为单栏布局。
实现步骤
-
布局设计:
- 在平板模式下,使用
LinearLayout
水平排列两个 Fragment。 - 在手机模式下,仅显示列表 Fragment,点击后跳转到详情界面。
<!-- layout-sw600dp/activity_main.xml --> <LinearLayout android:orientation="horizontal"> <fragment android:name="com.example.ListFragment" android:id="@+id/list_fragment" android:layout_weight="1"/> <fragment android:name="com.example.DetailFragment" android:id="@+id/detail_fragment" android:layout_weight="2"/> </LinearLayout>
- 在平板模式下,使用
-
动态替换逻辑:
当列表项被点击时,根据屏幕尺寸决定是否替换 Fragment:// 在 ListFragment 中 private fun onItemClick() { if (isTablet()) { // 自定义判断逻辑 // 通知 DetailFragment 更新内容 } else { // 启动新的 Activity 或替换当前 Fragment activity?.supportFragmentManager?.beginTransaction() ?.replace(R.id.container, DetailFragment.newInstance()) ?.addToBackStack(null) ?.commit() } }
最佳实践与常见问题
1. 避免内存泄漏
在 Fragment 中持有 Activity 的强引用可能导致内存泄漏。解决方案包括:
- 使用
WeakReference
包裹 Activity。 - 在
onDetach()
中清除回调。
2. 生命周期冲突
当 Activity 被销毁后,Fragment 的 onCreateView()
可能重复调用。此时需要通过 savedInstanceState
恢复数据:
override fun onCreateView(...) {
if (savedInstanceState != null) {
// 恢复数据
}
}
3. 灵活适配不同屏幕
通过 Configuration
判断屏幕尺寸,并动态调整 Fragment 的布局:
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
// 更新布局
}
}
结论
Android 碎片(Fragment) 是构建现代化、可扩展 Android 应用的核心工具。通过合理设计 Fragment 的生命周期、交互逻辑和布局适配,开发者可以轻松实现复杂界面的模块化开发。无论是基础的列表详情页,还是复杂的嵌套结构,Fragment 都能提供灵活且高效的支持。随着对这一概念的深入理解,读者将能够更自信地应对各种 UI 设计挑战,同时提升代码的可维护性和复用性。
提示:
在实际开发中,建议结合 Jetpack Compose 的Navigation
组件,探索现代 Android 开发的 Fragment 替代方案,但传统 Fragment 仍然是理解组件化设计的重要基础。