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 的核心优势在于:

  1. 模块化设计:将界面拆分后,代码更清晰,维护更方便。
  2. 响应式布局:根据屏幕尺寸或设备类型动态调整 Fragment 的排列方式(如平板与手机的布局差异)。
  3. 代码复用:同一 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()

实际案例:实现一个动态界面

场景描述

设计一个新闻应用,主界面包含左右两栏:左边是文章列表,右边是文章详情。当屏幕宽度不足时,切换为单栏布局。

实现步骤

  1. 布局设计

    • 在平板模式下,使用 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>
    
  2. 动态替换逻辑
    当列表项被点击时,根据屏幕尺寸决定是否替换 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 仍然是理解组件化设计的重要基础。

最新发布