「精华」Fragment 从入门到实战:带你彻底搞懂 Android 模块化开发!

「精华」Fragment 从入门到实战:阿里大佬带你彻底搞懂 Android 模块化开发!


目录

  1. 概述
  2. Fragment vs Activity
  3. 基本使用步骤
  4. Fragment 事务
  5. Fragment 与 Activity 通信
  6. Fragment 返回栈
  7. 实战:双 Fragment 布局

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

对比ActivityFragment
窗口有独立窗口没有窗口,寄生在 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()
        }
    }
}

总结

  1. Fragment 是寄生组件,没有独立窗口,必须依附 Activity
  2. 通过 FragmentManager 管理,使用事务进行添加/替换/删除
  3. 通信通过 Activity 中转,Fragment 之间不直接通信
  4. 返回栈需要手动管理,使用 addToBackStack() 添加
  5. 生命周期跟 Activity 绑定,但有自己独特的方法(onCreateView、onViewCreated 等)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值