为什么要使用碎片,以及何时使用碎片而不是活动?

625
在Android API 11+中,Google发布了一个新的类叫做Fragment
在视频中,Google建议我们尽可能使用片段而不是活动(link1link2),但他们没有详细解释为什么。
除了一些可以通过简单的视图/布局轻松实现的UI示例之外,片段的目的是什么以及可能的用途是什么?
我的问题是关于片段的:
1.使用片段有什么目的? 2.与使用活动/视图/布局相比,使用片段的优缺点是什么?
奖励问题:
3.你能给出一些真正有趣的片段用途吗?Google在他们的视频中没有提到的事情? 4.在片段和包含它们的活动之间进行通信的最佳方法是什么? 5.当使用片段时需要记住的最重要的事情是什么?您有哪些经验的提示和警告?

3
可能是 Dilemma: when to use Fragments vs Activities: 的重复问题。 - Ciro Santilli OurBigBook.com
一个活动可以被视为独立的微服务,而片段可以被视为可嵌入的依赖项。 - Abhinav Atul
13个回答

358
#1&#2使用片段的目的是什么,相比于使用活动/视图/布局,使用片段的优缺点是什么?
片段是Android创建可重用用户界面的解决方案。您可以使用活动和布局实现一些相同的功能(例如使用包含)。但是,从HoneyComb开始,片段已经被纳入到Android API中。让我详细说明;
ActionBar。如果您想要在那里使用选项卡来导航应用程序,则会快速看到ActionBar.TabListener接口将FragmentTransaction作为输入参数传递给onTabSelected方法。您可能可以忽略此功能并执行其他操作,但这样做将不利于API而非与其合作。
FragmentManager以非常巧妙的方式为您处理后退。回退并不意味着返回到上一个活动,就像对于常规活动一样。它意味着返回到先前的片段状态。
您可以使用酷炫的ViewPager和FragmentPagerAdapter创建滑动界面。FragmentPagerAdapter代码比常规适配器更清晰,并且它控制个别片段的实例化。
如果您尝试为手机和平板电脑同时创建应用程序,则使用片段将使您的工作变得轻松得多。由于片段与Honeycomb+ API密切相关,因此您还需要在手机上使用它们以重用代码。这就是兼容库派上用场的地方。
即使您打算为手机应用程序使用片段,也应该如此。如果您考虑到可移植性。我使用ActionBarSherlock和兼容库创建“ICS外观”的应用程序,从1.6版本开始都是相同的。您将获得最新功能,例如带有选项卡、溢出、拆分操作栏、视图页面等ActionBar。

在Fragment之间进行通信的最佳方式是使用意图。当您在Fragment中按下某个东西时,通常会使用具有数据的StartActivity()来调用它。该意图将传递给您启动的所有活动的片段。


9
首先,感谢您。我欣赏那些能够提供简洁但信息丰富的答案而不只是给我一个手册链接的人。无论如何,在除了处理特殊类别的额外功能之外,您能否想到使用片段的优缺点? - android developer
4
我认为你需要更直接地提问。上面我已经列出了四个主要优势。 - Glenn Bech
3
相比于自定义视图和活动,有哪些缺点呢? - android developer
79
一个片段不应直接与另一个片段交流,而是通过其父活动进行。这样,您就不会得到混乱的代码,而是易于管理的代码。 - slott
11
“在片段之间进行通信的最佳方式是使用意图(intents)”?嗯?我不这么认为。意图是用于在活动(activities)之间进行通信的。在“片段之间”进行通信的方式是...不要直接传递信息给另一个片段。也就是说,片段应该通过自定义接口回调其所属的活动(activity),由活动决定如何处理信息。请注意,此翻译尽量保持原文意思不变,并更加通俗易懂。 - ToolmakerSteve
显示剩余8条评论

85

不确定您所指的视频是哪些,但我怀疑它们并没有说你应该使用碎片(fragments)代替活动(activities),因为它们并不是直接可互换的。实际上,在开发者指南中有一个相当详细的条目,建议阅读以获取详细信息。

简而言之,碎片生存在活动中,每个活动可以托管多个碎片。与活动一样,它们具有特定的生命周期,但与活动不同的是,它们不是顶级应用组件。碎片的优点包括重复使用代码和模块化(例如,在许多活动中使用相同的列表视图),包括构建多窗格界面的能力(在平板电脑上非常有用)。主要缺点是一些额外的复杂性。通常情况下,您可以通过非标准和不太健壮的方式在(自定义)视图中实现相同的功能。


1
更新了问题。现在它有谷歌视频的链接。感谢解释,但我仍需要澄清我的问题。 - android developer
6
阅读开发者指南条目,其中有足够的细节。在stackoverflow上不太可能得到“片段的酷炫用法”的答案——太模糊了,也没有一个单一的答案。第四个问题在开发者指南中有特别的回答——http://developer.android.com/guide/topics/fundamentals/fragments.html#CommunicatingWithActivity - Nikolay Elenkov
1
据我所知,这个方法会创建一个依赖关系,指定哪个活动能够包含哪个片段。另外,请回答主要问题(前两个)。 - android developer
3
感谢安卓开发者坚持回答基础问题。就目前而言,我在 Fragment 类中并没有发现比使用 XML "include" 标记更有用的东西。我会觉得有价值的事情包括能够指定一个布局,在所有分辨率下自动变形为最佳用户体验的能力。根据我的了解,你仍然需要自己编写代码来实现这一点。另一个潜在的价值在于将代码和资源捆绑成可重用的组件,但似乎也不存在。我想知道一个真正好的理由。 - Melinda Green
2
我开始理解谷歌建议使用片段的方式,但我非常同意@NikolayElenkov的观点。对我来说,使用活动仍然似乎是最强大和最简单的方式。 - andrea.rinaldi
它仍然没有真正回答为什么不只使用自定义视图或片段与自定义视图有多大的区别,您可以在其中执行所有相同的操作并实现可重用性。答案是Google不希望您使用自定义视图,而是提供了片段。不幸的是,许多Android最佳实践选择都是这样的。 - Lassi Kinnunen

68

Fragment是应用程序用户界面或行为的一部分,可以放置在Activity中,从而实现更模块化的活动设计。如果我们说Fragment是一种子活动,也不会错。

以下是关于Fragment的重要点:

  1. Fragment具有自己的布局和自己的行为,具有自己的生命周期回调。

  2. 您可以在Activity运行时添加或删除Fragment。

  3. 您可以在单个Activity中组合多个Fragment以构建多窗格UI。

  4. 一个Fragment可以在多个Activity中使用。

  5. Fragment的生命周期与其宿主Activity的生命周期密切相关。

  6. 当Activity暂停时,所有可用的Fragment也会停止。

  7. Fragment可以实现没有用户界面组件的行为。

  8. Fragment是在Android 3(Honeycomb)中添加到Android API中的,API版本为11。

如需更多详细信息,请访问官方网站,Fragments


  1. 正如您在#8中提到的,它不必具有布局。
  2. 您错过了“means”后面的部分。无论如何,感谢您帮助其他人更清楚地理解这一点。我会给您+1。
- android developer
2
关于#8,无布局片段(即“无头”片段)的可能示例是执行任务的片段,尽管它有点短(例如短的HTTP请求),但仍需要在配置更改后保持活动状态,并因此依赖于确切的片段实例跨它们被保留(通过在片段上使用setRetainInstance(true))。至于布局片段,setRetainInstance(true)没有太多意义,因为它会防止与其视图相关联的资源在必要时被释放(即内存泄漏)。 - Piovezan
注意:"#8"现在是"#7"。 - ToolmakerSteve

40

活动是应用程序中具有工具栏的全屏组件,其他所有内容最好都是片段。 具有工具栏的一个全屏父活动可以有多个窗格、可滚动页面、对话框等(所有片段),这些都可以从父类访问并通过父类通信。

例如:

活动A、活动B、活动C:

  • 所有活动都需要重复相同的代码,例如显示基本的工具栏,或从父活动继承(管理起来很麻烦)。
  • 要从一个活动转移到另一个活动,要么需要将它们全部保留在内存中(开销大),要么需要销毁一个活动以打开另一个活动。
  • 活动之间的通信可以通过意图进行。

与此相比:

活动A、片段1、片段2、片段3:

  • 没有重复代码,所有屏幕都有工具栏等来自一个活动的元素。
  • 有多种方法从一个片段移动到下一个片段 - 视图分页器、多窗格等。
  • 活动拥有大部分数据,因此只需要最少的片段间通信。如果仍然需要,可以轻松地通过接口完成。
  • 片段不需要全屏幕,设计它们有很大的灵活性。
  • 如果视图不必要,则片段不需要填充布局。
  • 多个活动可以使用相同的片段。

3
完美回答! - Sathesh

33

这是我在片段上找到的重要信息:

历史上,Android应用程序中的每个屏幕都是作为单独的Activity实现的。这会在屏幕之间传递信息时创建问题,因为Android Intent机制不允许直接在Activities之间传递引用类型(即对象)。相反,必须对对象进行序列化或提供全局可访问的引用。

通过将每个屏幕作为单独的Fragment,完全避免了这种数据传递的麻烦。Fragments始终存在于给定Activity的上下文中,并且始终可以访问该Activity。通过将感兴趣的信息存储在Activity中,每个屏幕的Fragment可以简单地通过Activity访问对象引用。

来源:https://www.pluralsight.com/blog/software-development/android-fragments


3
没错,但是有解决方案:如果不是一个非常大的对象,可以使用Parcelable(还有一个插件可以让它更容易),如果是一个非常大的对象,你可以使用静态引用,当你到达新的活动时将其设置为null(或者根据需求在销毁活动时)。 - android developer
@androiddeveloper:"使用Parcelable"符合我对“通过使用Fragment避免数据传递头痛”的定义。如果有需要在一系列屏幕经过时持续存在的复杂共享状态,则Activity + Fragments是一个不错的解决方案,依IMHO而论。(尽管我放弃了Fragment返回栈,并自己管理了“返回”意味着什么。) - ToolmakerSteve
1
通过容器活动在片段之间使用接口设计模式是一种更模块化的方法,可以将不仅对象而且点击事件监听器和方法参数传递回其他片段或主容器活动。 - Kaveesh Kanwal

11

在某些情况下,碎片特别有用,比如我们想在所有页面中保留导航抽屉。您可以使用帧布局填充任何碎片,并仍然可以访问导航抽屉。

如果您使用了 Activity,那么您必须在所有 Activity 中保留抽屉,这会导致冗余代码。这是碎片的一个有趣用途。

我是Android新手,仍然认为碎片以这种方式很有用。


1
是的。然而,我有时仍会对正确使用片段感到困惑,这是由于片段和活动的复杂生命周期造成的。 - android developer
@androiddeveloper 你主要只使用活动吗? - Michael Alan Huff
@MichaelAlanHuff 当支持平板电脑时,我认为最好使用Fragments。此外,当支持方向更改和其他类似事件时,您可能希望使用DialogFragment,因为它允许您恢复它们。 - android developer
@androiddeveloper,我也是这么认为的。我没有经常使用DialogFragments。为了帮助逻辑的模块化,许多Android开发人员开始使用自定义视图来保存逻辑,就像Square的Mortar一样。这里有一个最近由Airbnb工程师关于自定义视图的演讲 https://vimeo.com/127799187 - Michael Alan Huff
@MichaelAlanHuff 如果您认为当前屏幕可以成为另一个屏幕的一部分,使用片段也可能很有用。 - android developer
实际上,你完全可以在同一个活动中创建视图或使用自定义视图,这样就没有任何阻碍了。而片段的作用是为你提供一些样板代码,以标准化的方式创建“自定义视图”。 当时,谷歌最佳实践的倡导者甚至没有提到创建自己的视图的可能性,因此才出现了片段。 - Lassi Kinnunen

5

我知道这个问题已经被讨论得很透彻了,但我想再添加一些观点:

  • Frags可用于填充Menu并处理MenuItem的点击事件。因此,您的Activity具有更多的模块化选项。你可以在不让Activity知道的情况下执行ContextualActionBar等操作,并且基本上可以将其与Activity处理的基本内容(Navigation/Settings/About)分离。

  • 拥有子Frag的父Frag可以给您更多的组件模块化选项。例如,您可以轻松地交换Frag,将新的Frag放入Pager中或删除它们,重新排列它们,而无需使Activity知道任何事情,只需专注于更高层次的内容即可。


4
Fragment可以被看作是UI元素组合树中非根组件,而活动则坐落在组合(UI树)森林的顶部。
以下是使用Fragment时不应该遵循的一些经验法则:当片段作为子项时具有冲突属性,例如它可能是沉浸式的或者完全使用了不同的样式,或者具有其他架构/逻辑差异,并且不符合现有的树的同质性特点。
以下是使用Activity优于Fragment时的经验法则:当任务(或一组连贯的任务)是完全独立和可重用的,做一些重量级的工作并且不应该再受到另一个父-子组合的限制时,就要优选Activity(SRP违例,第二个职责是符合组合)。例如,一个MediaCaptureActivity可以捕获音频、视频、照片等,并允许进行编辑,去噪,对照片进行注释等。这个活动/模块可能会有子片段来进行更细致的工作,并符合公共的显示主题。

3

一个Fragment存在于Activity内部,而一个Activity则是独立存在的。


8
"on itself"可以翻译为 "自身上",但更通常的说法是 "on its own" 或者 "by itself",意思是指某个事物单独存在或独立完成某项任务。 - Peter Mortensen

3

Fragment(片段)存在于Activity(活动)之内,具有:

  • 自己的生命周期
  • 自己的布局
  • 自己的子片段等。

将Fragment视为所属主Activity的子Activity,它不能独立存在,并且可以被多次调用/重复使用。希望这能帮到您 :)


实际上,关于第二点(“它自己的布局”),这是可选的。一个片段不必拥有任何视图。 - android developer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接