)
文档教程移动开发【免费下载链接】android-training-course-in-chineseAndroid官方培训课程中文版项目地址https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese点击查看免费下载本篇技术指南围绕《Android 官方培训课程中文版》android-training-course-in-chinese中 与其他 Fragment 交互 一课展开讲解在基于 Fragment 的动态 UI 架构下如何通过宿主 Activity 与回调接口实现 Fragment 之间的消息传递。读完本文你将掌握Fragment 内定义接口、onAttach() 中绑定实现、Activity 实现接口接收事件、findFragmentById() 反向传参这一完整链路并能写出兼容平板两窗格two-pane与手机单窗格one-pane布局的新闻阅读器式应用。Fragment 通信架构原则自包含组件交互只经宿主 Activity为了最大化复用 Fragment UI 组件每一个 Fragment 都应被构建成完全自包含、模块化的组件自己定义布局、自己管理行为。当多个这样的可复用 Fragment 组合进同一个 Activity 时Activity 便承担起复合 UI的组装职责。本课给出的核心架构铁律是所有 Fragment 之间的交互都应通过与之关联的 Activity 来完成两个 Fragment 之间不应直接交互。例如当用户在新闻标题列表 Fragment中点击某一条目时列表 Fragment 不应直接去修改右侧文章内容 Fragment的界面而是先把事件上抛给 Activity由 Activity 决定下一步做什么更新右侧 Fragment或替换整个界面。这种自下而上回调、自上而下派发的模式让 Fragment 之间保持零耦合任何一个 Fragment 都可以被换掉、复用到别的 Activity 中而不会破坏整体逻辑。第一步在 Fragment 中定义回调接口要让 Fragment 与容器 Activity 交互标准做法是在 Fragment 类内部定义一个接口由宿主 Activity 实现它。Fragment 在自己的onAttach()生命周期方法中获取该接口的实现即宿主 Activity 本身之后随时可以调用接口方法向 Activity 发消息。译注onAttach()是 Fragment 与 Activity 关联时自动触发的生命周期回调只要 Fragment 中实现了onAttach()方法系统就会在它被附加到 Activity 时自动调用。以新闻标题列表Fragment 为例完整代码如下public class HeadlinesFragment extends ListFragment { OnHeadlineSelectedListener mCallback; // 容器 Activity 必须实现该接口 // 译注容器 Activity意即包含该 Fragment 的 Activity public interface OnHeadlineSelectedListener { public void onArticleSelected(int position); } Override public void onAttach(Activity activity) { super.onAttach(activity); // 确认容器 Activity 已实现该回调接口。否则抛出异常 try { mCallback (OnHeadlineSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() must implement OnHeadlineSelectedListener); } } ... }关键点拆解接口定义在 Fragment 内部OnHeadlineSelectedListener使回调契约与触发方天然绑定便于阅读和维护onAttach()中做强制类型转换将宿主 Activity 强转为接口类型并存入成员变量mCallbacktry/catch捕获ClassCastException如果容器 Activity 忘了实现该接口会在 Fragment 附加时立即以清晰、可定位的异常信息暴露出来例如 com.example.MainActivity must implement OnHeadlineSelectedListener而不是等到用户点击时才出现莫名其妙的空指针或类型错误。兼容性说明本课程基于 Android Support Library v4 时代的 API 编写参见 basics/fragments/creating.md 中import android.support.v4.app.Fragment的写法。在更高 API 级别中onAttach(Activity)已被onAttach(Context context)取代判断逻辑通常改写为if (context instanceof OnHeadlineSelectedListener)后再赋值思路完全相同。定义好接口后Fragment 就通过mCallbackOnHeadlineSelectedListener的实例随时向 Activity 传递消息。例如当用户点击列表条目时触发下方回调Override public void onListItemClick(ListView l, View v, int position, long id) { // 向宿主 Activity 传送事件 mCallback.onArticleSelected(position); }ListFragment在用户点击列表项时自动调用onListItemClick()这里把position被点击条目的索引作为参数上抛给宿主 Activity。Fragment 自身完全不知道也不关心 Activity 收到后要做什么——解耦由此达成。第二步宿主 Activity 实现接口并接收回调要接收回调事件宿主 Activity 必须声明implements该 Fragment 中定义的接口并提供接口方法的实现public static class MainActivity extends Activity implements HeadlinesFragment.OnHeadlineSelectedListener{ ... public void onArticleSelected(int position) { // 用户从 HeadlinesFragment 选择了一篇文章的标题 // 在这里做点什么以显示该文章 } }至此事件链已经完整闭合用户点击列表项 →onListItemClick()被调用Fragment 调用mCallback.onArticleSelected(position)mCallback实际指向宿主 Activity → Activity 的onArticleSelected()被触发Activity 在回调中编排下一步 UI 操作。值得注意由于onAttach()中做过类型校验Activity 若漏写implements会在运行早期抛出明确的异常而这里onArticleSelected(int position)的实现就是复合 UI逻辑真正落地的位置。第三步Activity 向 Fragment 传递消息回调把用户选了哪篇文章送进了 Activity。接下来 Activity 需要把这条消息反向推送给负责展示文章内容的 Fragment。手段是通过findFragmentById()获取 Fragment 实例再直接调用它的 public 方法。例如假设 Activity 中还包含另一个用于展示文章详情的 FragmentArticleFragmentActivity 就可以在回调中拿到被选位置的数据并转发给它。完整示例含两窗格与单窗格两种分支处理public static class MainActivity extends Activity implements HeadlinesFragment.OnHeadlineSelectedListener{ ... public void onArticleSelected(int position) { // 用户从 HeadlinesFragment 选择了一篇文章的标题 // 在这里做点什么以显示该文章 ArticleFragment articleFrag (ArticleFragment) getSupportFragmentManager().findFragmentById(R.id.article_fragment); if (articleFrag ! null) { // 若 articleFrag 有效则表示我们正在处理两格布局two-pane layout…… // 调用 ArticleFragment 的方法以更新其内容 articleFrag.updateArticleView(position); } else { // 否则我们正在处理单格布局one-pane layout。此时需要 swap frags... // 创建 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 替换它。并将 // 该事务添加至回栈以便用户可以往回导航译注回栈即 Back Stack。 // 在有多个 Activity 的 APP 中将这些 Activity 按创建次序组织起来的 // 栈称为回栈 transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // 执行事务 transaction.commit(); } } }这段代码展示了两种典型分支对应两种屏幕布局策略分支一两窗格布局two-pane。findFragmentById(R.id.article_fragment)返回非空说明平板等宽屏上ArticleFragment已经静态地躺在布局里。此时无需创建新实例直接调用其 public 方法updateArticleView(position)就地刷新内容即可——两个 Fragment 依旧互不直接引用消息由 Activity 中转。分支二单窗格布局one-pane。手机上R.id.article_fragment不存在返回null。此时需要动态换屏新建ArticleFragment把被选位置position放进Bundle再通过setArguments(args)绑定给新 Fragment最后用FragmentTransaction执行replace(R.id.fragment_container, newFragment)addToBackStack(null)commit()。这样用户按返回键时事务会从回栈弹出界面撤销回列表页。两种传参方式的语义区别值得强调setArguments(Bundle)在 Fragment 创建前注入参数参数会被系统在 Activity 重建、Fragment 重新附加时保留与savedInstanceState协同工作适合初始数据调用 public 方法如updateArticleView(position)适合更新已存在 Fragment 的运行时状态。配套布局两窗格与单窗格布局是如何定义的本课默认读者已完成前两课basics/fragments/creating.md 与 basics/fragments/fragment-ui.md其中给出了与上述代码一一对应的布局方案这里一并梳理**宽屏平板**使用res/layout-large/news_articles.xml通过 XML 一次性静态放置两个 Fragment并用layout_weight分配宽度来自 basics/fragments/creating.mdLinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:orientationhorizontal android:layout_widthfill_parent android:layout_heightfill_parent fragment android:namecom.example.android.fragments.HeadlinesFragment android:idid/headlines_fragment android:layout_weight1 android:layout_width0dp android:layout_heightmatch_parent / fragment android:namecom.example.android.fragments.ArticleFragment android:idid/article_fragment android:layout_weight2 android:layout_width0dp android:layout_heightmatch_parent / /LinearLayout这里id/article_fragment正是上一节findFragmentById()要查找的 IDlayout_weight2使文章区占三分之二宽度。**手机小屏**使用同名但位于无large限定符目录下的res/layout/news_articles.xml只放一个空的FrameLayout作为 Fragment 容器来自 basics/fragments/fragment-ui.mdFrameLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:idid/fragment_container android:layout_widthmatch_parent android:layout_heightmatch_parent /两窗格与单窗格的差异正是上节回调代码中findFragmentById()判空分支的存在原因。下图直观展示了同一 Activity 在不同屏幕尺寸下的两种配置图1两个 Fragment 显示在不同尺寸屏幕上同一 Activity 的不同配置中。宽阔屏幕上两个 Fragment 并列显示手机上一次只能显示一个必须在用户导航时替换 Fragment图片来自 basics/fragments/fragment-ui.md。另外onCreate()中运行时添加初始 Fragment 时务必先检查savedInstanceState ! null就提前返回避免 Activity 重建后叠加重叠的 Fragment详见 basics/fragments/fragment-ui.md 的MainActivity示例。最佳实践与注意事项汇总综合本课及配套课程可沉淀出以下可直接落地到项目的实践要点Fragment 永不直接互调。所有跨 Fragment 的消息一律经宿主 Activity 中转否则组件无法独立复用也难以测试。接口校验前置到onAttach()。用try/catch包裹强转宿主未实现接口时立刻抛出ClassCastException错误信息中带上 Activity 类名排障成本最低。先判空再更新。对静态存在的 Fragment 使用findFragmentById()前先判空以区分两窗格/单窗格布局避免在单窗格设备上 NPE。addToBackStack(null)的语义来自 basics/fragments/fragment-ui.md移除或替换 Fragment 并加入回栈时被移除的 Fragment 是停止而非销毁用户按返回键可还原不加入回栈则会直接销毁。addToBackStack()的可选字符串参数仅供FragmentManager.BackStackEntry高级操作使用常规场景传null即可。支持库 API 的选择支持 Android 1.6API level 4及以上设备时Activity 需继承FragmentActivity并使用getSupportFragmentManager()最低版本 ≥ 11 可用原生Activity若引入 v7 appcompat 库则应继承AppCompatActivity其本身是FragmentActivity的子类参见 basics/fragments/creating.md。静态fragment标签的限制通过 XML 静态添加的 Fragment 无法在运行时移除或替换因此凡需要换屏的交互场景都必须走FragmentTransaction动态添加/替换的路线。本章在课程中的位置本课是 basics/fragments/index.md使用 Fragment 建立动态 UI三课中的收官一课前两课分别解决创建 Fragmentbasics/fragments/creating.md与运行时动态增删替换basics/fragments/fragment-ui.md。将三课连起来即得到一个完整的、基于 Fragment 的响应式多窗格新闻阅读器实现思路全书的课程导航见 SUMMARY.md。官方配套的完整示例工程名为 FragmentBasics建议边读本课边对照示例中的MainActivity、HeadlinesFragment与ArticleFragment三个类验证本文所述的回调链路。赞分享文档教程移动开发【免费下载链接】android-training-course-in-chineseAndroid官方培训课程中文版项目地址https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese点击查看免费下载相关推荐Android 应用间交互完全指南使用 Intent 启动其他应用、接收返回结果与暴露 Activityandroid-training-course-in-chineseAndroid 应用间交互完全指南使用 Intent 启动其他应用、接收返回结果与暴露 Activityandroid training course in文档教程移动开发Android Activity 重新创建与实例状态保存恢复全解析android-training-course-in-chineseAndroid Activity 重新创建与实例状态保存恢复全解析android training course in chinese 本指南基于 andr文档教程移动开发Android Activity 生命周期全解析基于 android-training-course-in-chinese 的回调机制、状态迁移与实例状态保存实战Android Activity 生命周期全解析基于 android training course in chinese 的回调机制、状态迁移与实例状态保存文档教程移动开发上一篇Box2D终极性能指南AVX2 vs SSE2对比分析下一篇Maestro快速跑通移动 UI 自动化测试创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考