- 文档
- 教程
- 移动开发
【免费下载链接】android-training-course-in-chinese
Android官方培训课程中文版
本文基于 android-training-course-in-chinese 仓库中 basics/fragments/creating.md 课程,结合同章节的 fragment-ui.md、communicating.md 以及仓库内 Action Bar、多屏幕适配等关联资料,系统讲解如何创建 Fragment、将其集成进 Activity,并在低版本 Android 上保持兼容。
导读
Fragment 是 Android 中可复用的模块化 UI 组件,可以把它想象成"Activity 的模块":它拥有自己的生命周期,能够接收输入事件,可以在 Activity 运行过程中被添加或移除,并且能在不同 Activity 中重复使用。本指南将教你创建第一个 Fragment 类、通过 XML 布局将其声明式地嵌入 Activity,并解决低版本 Android(最低至 1.6)的兼容性问题。读完本文,你将掌握 Fragment 类编写、布局资源组织、FragmentActivity/AppCompatActivity的正确选型,以及"XML 静态声明"与"运行时动态事务"两种集成方式的差异与取舍。
一、课前准备:引入 Support Library
Fragment 自 Android 3.0(API level 11)起才作为平台 API 加入。为了让应用在 Android 1.6 这样的低版本上也能使用 Fragment,必须引入 Support Library:
- 最基础的做法是使用v4支持库,其中包含了
android.support.v4.app.Fragment、android.support.v4.app.FragmentActivity等一系列关键类; - 也可以直接使用包含APP Bar能力的v7 appcompat库。该库兼容 Android 2.1(API level 7),同时也完整包含了 Fragment API,并额外提供了
AppCompatActivity与Theme.AppCompat主题体系。
仓库中 basics/actionbar/setting-up.md 给出了 v7 appcompat 的接入要点:引入库之后,Activity 改为继承
ActionBarActivity(即后来AppCompatActivity的前身),并在 Manifest 中为<application>或<activity>指定Theme.AppCompat(或其子类如Theme.AppCompat.Light)主题,同时将minSdkVersion设置为7、targetSdkVersion按需设置,即可让应用在 Android 2.1 及以上版本拥有 Action Bar 与 Fragment 能力。
二、创建 Fragment 类
创建 Fragment 的第一步是从Fragment继承并编写自己的子类,然后在关键生命周期方法中插入代码——处理方式与 Activity 完全一致。
2.1 唯一的必需回调:onCreateView()
创建 Fragment 时,必须重写onCreateView()回调方法来定义布局。事实上,这是为了让一个 Fragment 运行起来唯一需要重写的回调方法。onCreateView()负责为 Fragment 填充布局,其返回值是 Fragment 对应的根View。
下面是一个自定义布局的 Fragment 示例(对应原文档中的ArticleFragment):
import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.ViewGroup; public class ArticleFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // 拉伸该 Fragment 的布局 return inflater.inflate(R.layout.article_view, container, false); } }这里的要点:
inflater.inflate(R.layout.article_view, container, false)第三个参数为false,表示不将填充结果自动挂载到container上。Fragment 的视图最终由 FragmentManager 负责挂载,若此处传入true会造成视图重复添加;container是 Activity 布局中用于承载该 Fragment 的父容器(ViewGroup),系统会在合适时机将其作为onCreateView的参数传入;savedInstanceState用于在重建时恢复 Fragment 的保存状态,与 Activity 的机制类似。
2.2 生命周期与 Activity 同步
和 Activity 一样,当 Fragment 从 Activity 添加或移除、或 Activity 生命周期发生变化时,Fragment 通过生命周期回调方法管理自身状态。关键规律是:Fragment 的生命周期与宿主 Activity 绑定。例如,当 Activity 的onPause()被调用时,其内部所有 Fragment 的onPause()方法也会被触发。
关于 Fragment 完整的生命周期与回调方法清单,可进一步参考仓库中 basics/fragments/index.md 课程的后续内容(onStart、onResume、onStop、onDestroyView、onDetach等),其中onDestroyView用于释放 Fragment 视图相关资源,onDetach在 Fragment 与 Activity 解除关联时调用。
三、用 XML 将 Fragment 添加到 Activity
Fragment 是可重用、模块化的 UI 组件。每个 Fragment 实例都必须与一个FragmentActivity关联。最直接的关联方式,就是在 Activity 的 XML 布局文件中用<fragment>标签逐个声明 Fragment。
兼容性注记:
FragmentActivity是 Support Library 提供的特殊 Activity 基类,专门用于在 API level 11 以下的系统上承载 Fragment。如果你的应用minSdkVersion >= 11,可以直接使用普通的Activity(平台原生的 Fragment 支持自 11 起可用)。
3.1 为不同屏幕准备不同布局
原文档展示了一个典型场景:当屏幕被判定为 "large"(通过布局目录名称中的large限定符区分)时,在布局中同时放置两个 Fragment,形成左右并排的双窗格界面:
res/layout-large/news_articles.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <fragment android:name="com.example.android.fragments.HeadlinesFragment" android:id="@+id/headlines_fragment" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.android.fragments.ArticleFragment" android:id="@+id/article_fragment" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout>布局要点:
<fragment>标签的android:name属性必须填写Fragment 类的完整限定名(包名 + 类名),系统据此实例化对应的 Fragment;android:id用于之后通过findFragmentById()定位该 Fragment;- 两个 Fragment 分别设置
layout_weight为 1 和 2、宽度为0dp,从而按 1:2 的比例均分横向空间(新闻列表占 1/3,文章正文占 2/3); layout-large目录限定符保证该双窗格布局只在大屏设备上生效。
仓库中 ui/multiscreen/screen-sizes.md 对"尺寸限定词"机制有更系统的讲解:除了
large,还可以使用sw600dp等最小宽度限定符,在运行时根据设备配置选择最合适的布局资源。同目录还展示了新闻阅读器示例中在单个布局里直接声明<fragment>(com.example.android.newsreader.HeadlinesFragment)的用法。
3.2 在 Activity 中加载该布局
将这个布局文件应用到 Activity 中。使用 v4 支持库时,Activity 必须继承自FragmentActivity:
import android.os.Bundle; import android.support.v4.app.FragmentActivity; public class MainActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.news_articles); } }如果使用的是v7 appcompat 库,则 Activity 应改为继承自AppCompatActivity——它是FragmentActivity的子类,在保留全部 Fragment 能力的同时额外提供 Action Bar / App Bar 支持(仓库 basics/actionbar/setting-up.md 详细介绍了配套的Theme.AppCompat主题与 Manifest 配置)。
3.3 静态声明的限制
重要限制:当通过 XML 布局文件的方式(
<fragment>标签)将 Fragment 添加进 Activity 时,该 Fragment 不能被动态移除。如果你需要在用户交互时把 Fragment 切入切出,就必须在 Activity 启动之后、通过代码运行时添加 Fragment。这部分内容正是同章节 basics/fragments/fragment-ui.md 的主题。
四、进阶:运行时动态添加与替换 Fragment
虽然 XML 静态声明简单直接,但它不具备动态性。要实现"在手机上一次只显示一个 Fragment、通过导航切换"这类体验,必须使用 FragmentManager + FragmentTransaction 在运行时操作 Fragment。示意图(basics/fragments/fragments-screen-mock.png)清晰地展示了同一 Activity 在不同尺寸屏幕上的两种配置:平板上两个 Fragment 并列显示,手机上则依次单窗格展示。
图1:两个 Fragment 在不同尺寸屏幕上的布局配置——大屏并列显示,小屏依次切换
4.1 准备容器:FrameLayout
运行时添加 Fragment 时,必须在 Activity 布局中提供一个作为容器的View。典型的做法是用一个空的FrameLayout作为占位容器。下面这个布局文件与 3.1 节的文件同名(news_articles.xml),但放在不带large限定符的普通layout目录下,因此会在屏幕小于 "large" 的设备上被选用:
res/layout/news_articles.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" />4.2 在 onCreate() 中添加初始 Fragment
添加或移除 Fragment 的事务通过FragmentManager创建FragmentTransaction完成。流程为:调用getSupportFragmentManager()获取 FragmentManager → 调用beginTransaction()创建事务 → 调用add()添加 Fragment → 调用commit()提交。同一个FragmentTransaction可以承载多个 Fragment 操作。
import android.os.Bundle; import android.support.v4.app.FragmentActivity; public class MainActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.news_articles); // 确认 Activity 使用的布局版本包含 fragment_container FrameLayout if (findViewById(R.id.fragment_container) != null) { // 如果要从先前的状态还原,则直接返回,否则会得到重叠的 Fragment if (savedInstanceState != null) { return; } // 创建一个要放入 Activity 布局中的新 Fragment HeadlinesFragment firstFragment = new HeadlinesFragment(); // 如果此 Activity 是通过 Intent 发出的特殊指令启动的, // 将 Intent 的 extras 以参数形式传递给该 Fragment firstFragment.setArguments(getIntent().getExtras()); // 将该 Fragment 添加到 "fragment_container" FrameLayout 中 getSupportFragmentManager().beginTransaction() .add(R.id.fragment_container, firstFragment).commit(); } } }这段代码中值得注意的细节:
findViewById(R.id.fragment_container) != null用于区分当前使用的是双窗格布局还是单窗格布局,是"同一 Activity 适配多屏"的惯用手法;savedInstanceState != null时直接return,避免系统在旋转重建时把 Fragment 重复添加;setArguments()传参方式优于直接调用 Fragment 的 setter 方法:参数随 Fragment 一起被系统保存和恢复,是官方推荐的数据传递方式(配合onCreate/onCreateView中的getArguments()读取)。
4.3 替换 Fragment 与返回栈
替换 Fragment 与添加步骤相似,只是把add()换成replace()。在执行替换或移除等事务时,为了让用户能够向后导航并"撤消"更改,需要调用addToBackStack()后再提交事务:
// 创建 Fragment 并添加参数,指定应显示的文章 ArticleFragment newFragment = new ArticleFragment(); Bundle args = new Bundle(); args.putInt(ArticleFragment.ARG_POSITION, position); newFragment.setArguments(args); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); // 将 fragment_container 中的内容替换为此 Fragment, // 然后将该事务添加到返回栈,以便用户可以向后导航 transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // 执行事务 transaction.commit();关于返回栈,原文档给出了一条关键的行为差异:
注:当你移除或替换 Fragment 并向返回栈添加事务时,被移除的 Fragment 会停止(stop)而不是销毁。用户向后导航还原该 Fragment 时,它会重新启动;如果你没有向返回栈添加事务,那么该 Fragment 在移除或替换时就会被销毁。
addToBackStack()还可接收一个可选的字符串参数为事务命名,供FragmentManager.BackStackEntryAPI 进行高级操作时使用;普通场景传null即可。
五、配套实践:Fragment 与 Activity 的交互
Fragment 的价值在于复用与模块化。为保证每个 Fragment 完全自包含,所有 Fragment 之间的交互都应通过宿主 Activity 完成,两个 Fragment 不应直接通信。仓库中 basics/fragments/communicating.md 给出了标准的"接口回调"模式,与本文创建的HeadlinesFragment/ArticleFragment示例一脉相承:
- Fragment 定义接口并在 onAttach() 中获取实现——在
onAttach(Activity)中将宿主 Activity 强转为接口类型,失败则抛出ClassCastException,实现"容器必须实现该接口"的契约校验; - Activity 实现接口接收回调——例如
MainActivity implements HeadlinesFragment.OnHeadlineSelectedListener,在onArticleSelected(int position)中响应点击事件; - Activity 通过
findFragmentById()找到目标 Fragment 并直接调用其 public 方法——如果拿到的是双窗格布局中的现有 Fragment 就直接更新;否则新建 Fragment、setArguments传参、replace()+addToBackStack()完成单窗格切换。这与 4.3 节的替换代码完全一致,形成了"创建 → 静态/动态集成 → 交互"的完整闭环。
六、小结:两种集成方式的选型对照
| 对比维度 | XML 静态声明(<fragment>标签) | 运行时事务(FragmentManager) |
|---|---|---|
| 定义位置 | Activity 布局文件中 | Java 代码中 |
| 是否可动态移除/替换 | 不可 | 可以 |
| 典型场景 | 大屏双窗格固定布局 | 手机单窗格切换、动态 UI |
| 关键 API | setContentView(R.layout.news_articles) | getSupportFragmentManager().beginTransaction().add()/replace()...commit() |
| 兼容前提 | FragmentActivity(v4)或AppCompatActivity(v7) | 同上 |
本课所学的 Fragment 创建、XML 集成与生命周期知识,是后续"构建有弹性的 UI(fragment-ui.md)"与"与其他 Fragment 交互(communicating.md)"两课的基础。掌握"静态声明 + 动态事务 + 接口回调"这套组合拳,你就能用同一套 Fragment 代码为手机与平板提供差异化的自适应体验。
- 文档
- 教程
- 移动开发
【免费下载链接】android-training-course-in-chinese
Android官方培训课程中文版
相关推荐
Kafka KRaft 集群如何管理 SCRAM 凭据:一套完整操作指南
Kafka KRaft 集群如何管理 SCRAM 凭据:一套完整操作指南 在 Apache Kafka 的 KRaft 模式下启用 SASL/SCRAM 认证,
文档教程移动开发使用 GitHub Actions 集成 Checkov:在 CI 中自动扫描 IaC 安全合规
使用 GitHub Actions 集成 Checkov:在 CI 中自动扫描 IaC 安全合规 Checkov 是 Bridgecrew 推出的基础设施即代码
文档教程移动开发rrule.js与前端框架整合:React、Vue、Angular中的最佳实践
rrule.js与前端框架整合:React、Vue、Angular中的最佳实践 rrule.js是一个功能强大的JavaScript库,用于处理日历日期的重复规
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考