Fragment(碎片)是 Android 开发中核心的模块化组件,自 Android 3.0(API 11)引入以来,一直是解决屏幕适配、页面模块化拆分的核心方案。相比于 Activity,Fragment 更轻量、可复用性更强,能让复杂页面拆分为独立模块,大幅提升代码的可维护性。
一、什么是Fragment,Fragment的优势
Fragment 是嵌入在Activity中的模块化组件,拥有自己的生命周期、布局和逻辑,但不能独立存在,依赖 Activity 的 Contenxt,必须依附于 Activity。可以把 Activity 想象成一个相框,而 Fragment 就是相框里的照片。一个 Activity可以包含多个 Fragment,一个 Fragment 也可以被多个 Activity 复用。
Fragment 的优势在于:
- 模块化:复杂页面(如电商详情页)可拆分为 "标题 Fragment + 商品信息 Fragment + 评论 Fragment",各模块独立开发维护
- 复用性强:同一个 Fragment 可在不同 Activity 中复用(如搜索框 Fragment,既可以在首页用,也可以在个人中心用)
- 适配多屏幕:平板 / 折叠屏可同时显示多个 Fragment,手机端仅显示一个,无需写两套布局
- 灵活的生命周期:可独立控制显示 / 隐藏 / 替换,不影响 Activity 的生命周期
二、Fragment的基本使用
Fragment 分为静态注册(XML)和动态注册两种方式
创建基础 Fragment 类
java
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class FirstFragment extends Fragment {
// 静态创建实例(推荐:避免直接new,统一传参入口)
public static FirstFragment newInstance(String msg) {
FirstFragment fragment = new FirstFragment();
Bundle args = new Bundle();
args.putString("msg", msg);
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// 加载Fragment布局(第三个参数必须为false,避免直接添加到容器)
return inflater.inflate(R.layout.fragment_first, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// 初始化控件、数据(推荐在onViewCreated中做,而非onCreateView)
if (getArguments() != null) {
String msg = getArguments().getString("msg");
// 绑定文本框等操作
}
}
}
Fragment 的布局文件(XML)
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第一个Fragment"
android:textSize="20sp" />
</LinearLayout>
在Activity的布局文件中静态注册 Fragment,适合固定不变的 Fragment,缺点是无法动态控制显示/隐藏
XML
<!-- Activity的布局文件 activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 静态注册Fragment -->
<fragment
android:id="@+id/fragment_first"
android:name="com.example.fragmentdemo.FirstFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
在代码中动态注册 Fragment
java
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1. 获取Fragment管理器(必须用getSupportFragmentManager,兼容低版本)
FragmentManager fragmentManager = getSupportFragmentManager();
// 2. 开启事务(Fragment操作必须通过事务)
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 3. 创建Fragment实例(推荐用newInstance传参)
FirstFragment fragment = FirstFragment.newInstance("动态添加的Fragment");
// 4. 执行操作:添加Fragment到指定容器(R.id.fl_container是Activity布局中的空容器)
transaction.add(R.id.fl_container, fragment, "FirstFragment"); // tag用于后续查找
// 可选:添加到回退栈(按返回键时恢复Fragment,而非退出Activity)
transaction.addToBackStack("FirstFragment");
// 5. 提交事务(必须调用,否则操作不生效)
transaction.commit();
}
}
Activity 布局中需要预留空容器
XML
<!-- activity_main.xml -->
<FrameLayout
android:id="@+id/fl_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
常用的事务操作API:
add():添加 Fragment 到容器(可叠加多个);replace():替换容器中的 Fragment(先移除原有,再添加新的);hide()/show():隐藏 / 显示 Fragment(不销毁生命周期);remove():移除 Fragment(销毁生命周期);addToBackStack():加入回退栈,支持返回键恢复。
三、Fragment的生命周期
Fragment 的生命周期有:
|--------------------------|------------------------------------|
| 方法 | 触发时机 |
| onAttach() | Fragment 与 Activity 绑定成功时(仅执行 1 次) |
| onCreate() | Fragment 创建时(仅执行 1 次) |
| onCreateView() | 创建 Fragment 布局时 |
| onActivityCreated()(已废弃) | Activity 的 onCreate 执行完成后 |
| onViewCreated() | onCreateView 执行完成后 |
| onStart() | Fragment 可见时 |
| onResume() | Fragment 可交互时 |
| onPause() | Fragment 失去焦点时 |
| onStop() | Fragment 不可见时 |
| onDestroyView() | Fragment 的布局被销毁时 |
| onDestroy() | Fragment 实例销毁时 |
| onDetach() | Fragment 与 Activity 解绑时 |
常见场景下的生命周期变化
- Fragment 首次添加到 Activity
XML
onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume
- 横竖屏切换
XML
Fragment: onPause → onStop → onDestroyView → onDestroy → onDetach
Fragment: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume
- Fragment 被 replace
XML
原有Fragment: onPause → onStop → onDestroyView
新Fragment: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume
返回键恢复时
XML
新Fragment: onPause → onStop → onDestroyView
原有Fragment: onCreateView → onViewCreated → onStart → onResume
四、在Fragment中获取Activity结果
以前我们用 startActivityForResult,然后在 onActivityResult 里接数据。现在,官方推荐使用 ActivityResult API。
java
// 1. 定义ActivityResultLauncher(作为Fragment的成员变量直接初始化)
private ActivityResultLauncher<Intent> mLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
if (data != null) {
String resultStr = data.getStringExtra("result");
// 处理返回结果
}
}
}
);
// 2. 启动Activity
public void startSecondActivity() {
Intent intent = new Intent(getActivity(), SecondActivity.class);
intent.putExtra("data", "test");
mLauncher.launch(intent);
}
五、Fragment之间的通信
1. 共享ViewModel
java
// Fragment A 发送数据
val viewModel: SharedViewModel by activityViewModels()
viewModel.selectItem(item)
// Fragment B 接收数据
val viewModel: SharedViewModel by activityViewModels()
viewModel.selectedItem.observe(viewLifecycleOwner) { item ->
// 更新 UI
}
2. Fragment Result API
发送方(Fragment A):
java
setFragmentResult("requestKey", bundleOf("bundleKey" to "Hello!"))
接收方(Fragment B):
java
setFragmentResultListener("requestKey") { key, bundle ->
val result = bundle.getString("bundleKey")
// 处理结果
}
六、Fragment实现滑动
滑动切换 Fragment 是高频场景,推荐使用ViewPager2,支持横向/纵向滑动、RecyclerView 复用机制
Activity 布局
XML
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
自定义 FragmentStateAdapter
java
class MyAdapter(fragment: FragmentActivity) : FragmentStateAdapter(fragment) {
override fun getItemCount(): Int = 3
override fun createFragment(position: Int): Fragment = when(position) {
0 -> ChatFragment()
1 -> ContactFragment()
else -> SettingFragment()
}
}
Activity 中绑定 ViewPager2
java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager2 viewPager2 = findViewById(R.id.viewPager2);
// 设置适配器
viewPager2.setAdapter(new MyFragmentAdapter(this));
// 设置预加载页数(默认预加载1页,设为0可实现懒加载)
viewPager2.setOffscreenPageLimit(0);
}