困境:何时使用片段与活动:


785

我知道这Activities是为了代表我的应用程序的一个屏幕,而Fragments设计的它们是设计为可重用的UI布局,其中嵌入了逻辑。

直到不久前,我还开发了一个应用程序,因为它说应该进行开发。我创建了一个Activity来代表我的应用程序的屏幕,并将Fragments用于ViewPagerGoogle Maps。我很少创建ListFragment可以重复使用多次的UI或其他UI。

最近,我偶然发现了一个仅包含2 Activities个的项目,一个是SettingsActivity,另一个是MainActivity。的布局中MainActivity填充了许多隐藏的全屏UI片段,仅显示了一个。在Activity逻辑上有很多FragmentTransitions上,应用程序的不同屏幕之间。

我喜欢这种方法的原因在于,因为应用程序使用ActionBar,所以它保持不变并且不会随着屏幕切换动画而移动,Activity切换一样。这使这些屏幕过渡更加流畅。

因此,我想我想问的是与您分享有关此主题的当前开发方式,我知道乍一看它看起来像是一个基于意见的问题,但我将其视为一个Android设计和体系结构问题。基于意见的。

UPDATE(2014年5月1日):在此之后呈现由埃里克·伯克广场,(这是我不得不说是一个有很多的Android开发人员有用的工具,一个伟大的演示和我没有以任何方式广场相关)

http://www.infoq.com/presentations/Android-Design/

根据过去几个月的经验,我发现构建应用程序的最佳方法是创建片段组,以代表应用程序中的流程并将所有这些片段组合在一起Activity。因此,基本上Activities,您的应用程序中的流数将与流数相同。这样,动作栏在所有流程的屏幕上都保持不变,但是在更改流程时会重新创建,这很有意义。正如埃里克·伯克(Eric Burke)所言,以及我已经逐渐意识到的那样,尽可能少使用哲学Activities并不适用于所有情况,因为这在他所谓的“上帝”活动中造成了混乱。



Answers:


270

专家会告诉您:“当我看到UI时,我会知道是使用Activity还是Fragment”。一开始这没有任何意义,但是随着时间的流逝,您实际上将能够知道您是否需要Fragment

我发现有一种很好的做法对我很有帮助。当我试图向女儿解释一些事情时,发生在我身上。

即,想象一个代表屏幕的盒子。您可以在此框中加载另一个屏幕吗?如果使用新盒子,是否需要从第一个盒子复制多个项目?如果答案是肯定的,则应使用Fragments,因为根Activity可以容纳所有重复的元素,以节省创建它们的时间,并且您只需替换一下盒子的一部分即可。

但是请不要忘记,您始终需要一个盒装容器(Activity),否则您的零件将被分散。所以一个盒子里面有零件。

注意不要误用盒子。Android UX专家建议(您可以在YouTube上找到它们)何时应该显式加载another Activity,而不要使用a Fragment(例如当我们处理具有类别的Navigation Drawer时)。适应之后Fragments,您就可以观看他们的所有视频。甚至它们是强制性材料。

您现在可以看看您的UI并确定是否需要an Activity或a Fragment吗?您有新观点吗?我想你做到了。


4
您是否有提到的YouTube feed的链接?我搜索“ Android UX专家”和“ Android UX”,但不能完全确定您在谈论哪个视频。
我-

2
一年多以前没有看过。搜索Android开发者官方谈论UX
sandalone

1
考虑的一个示例:活动具有parentActivity,因此我们可以在从通知进入时合成Backstack,但是我不认为有这种parentFragment。
fikr4n


@ToolmakerSteve是的,它是getParentFragment,但这不是我的意思,请参见developer.android.com/guide/topics/manifest/…–
fikr4n

128

我的理念是:

仅在绝对必要时才创建活动。有了可用于提交一堆片段事务的后堆栈,我尝试在我的应用程序中创建尽可能少的活动。而且,各个片段之间的通信比在活动之间来回发送数据要容易得多。

活动转换非常昂贵,对吧?至少我相信这样-因为旧的活动必须被销毁/暂停/停止,被压入堆栈,然后新的活动必须被创建/开始/恢复。

自引入片段以来,这只是我的理念。


2
是的,但是正如您所写的,有时需要使用活动。一个示例是相机屏幕,最好在横向模式下使用它。另一个示例是在您放置自定义的appWidget(在“桌面”-启动器应用程序上)时显示的配置屏幕。
Android开发人员

感谢您的回答并分享您的经验。因此,您认为在Android中将应用程序限制为一个Activity并在应用程序体系结构允许的情况下在所有屏幕上使用Fragment是一个好习惯吗?
Emil Adz

1
那么,您如何解决需要彼此传递“状态”的碎片问题呢?您所有片段中的所有状态都必须处于一个活动中,否则您将被迫使用单例。
Mr_E

36
我不认为与各个活动之间来回发送数据相比,在各个片段之间进行通信要容易得多。
丹尼

3
至少,onActivityResult()比片段的回调更安全,更轻松。
CoolMind

59

好吧,根据Google的讲座(也许在这里,我不记得了),您应该考虑尽可能使用Fragments,因为它使您的代码更易于维护和控制。

但是,我认为在某些情况下它可能变得太复杂,因为承载片段的活动需要在片段之间进行导航/通信。

我认为您应该自己决定最适合您的。将活动转换为片段通常并不难,反之亦然。

我创建了一个关于这个dillema后在这里,如果你想读一些进一步。


5
感谢您的回答并分享您的经验。因此,您认为在Android中将应用程序限制为一个Activity并在应用程序体系结构允许的情况下在所有屏幕上使用Fragment是一个好习惯吗?
Emil Adz

它取决于项目,但是如果对您来说太复杂,您也可以将其分为多个活动。不要害怕使用任何一种方法。您也可以同时使用它们。有时候,使用片段而不是活动对您来说太困难了。我认为您应该尝试使用片段,但是如果以您的方式获取的片段过多,不要强迫它无处不在……
android developer

如果我想保持ActionBar的这种影响不变并且所有内容都被切换怎么办?通过活动能否实现这一目标?
Emil Adz


27

为什么在所有情况下我都更喜欢“片段”而不是“活动”。

  • 活动很昂贵。在“片段”中,视图和属性状态是分开的-每当片段在中时backstack,其视图将被销毁。因此,您可以堆叠比活动更多的碎片。

  • Backstack操纵。使用FragmentManager,很容易清除所有Fragment,插入比在Fragments等上更多的片段。但是对于Activity来说,操纵这些东西将是一场噩梦。

  • 可预测的生命周期。只要宿主Activity不被回收。后堆栈中的碎片将不会被回收。因此可以用来FragmentManager::getFragments()查找特定的Fragment(不鼓励使用)。


嗨,我看过您关于Frag优于Act的评论,您是否有任何项目可以在您的Github Repo中显示相同的内容?
Ümañgßürmån


12

我认为这并不重要。要考虑的关键因素是

  1. 您多久会重复使用部分UI(例如,菜单),
  2. 该应用程序也适用于平板电脑吗?

片段的主要用途是建立多窗格活动,使其非常适合Tablet / Phone响应式应用程序。


我要说的是,片段的主要用途是创建自定义视图,而不将其视为自定义视图。无论如何,这就是发生的事情。最初,片段是从Google展示的,它是制作平板电脑响应型应用程序的便捷方法,因此您可以根据需要将其固定在其他活动中。一种将代码或多或少地附加到视图,并使它们粘贴在您想要的位置的方式(无需创建自定义视图)。
Lassi Kinnunen

11

不要忘记,活动是可以通过Intent共享和启动的应用程序块/组件!因此,应用程序中的每个活动都只能解决一种任务。如果您的应用程序中只有一项任务,那么我认为您只需要一项活动,如果需要,还可以包含许多片段。当然,您可以在将来的活动中重用片段,以解决其他任务。这种方法将任务与逻辑清晰地分离。而且,您无需为不同的片段集使用不同的意图过滤器参数来维护一项活动。您可以根据需求在开发过程的设计阶段定义任务。


在我们的应用程序中,活动的一种任务是握住导航抽屉以输入不同的片段。:)为什么我要努力解决碎片问题?对全局数据持有对“全局”数据类的静态引用,并将某些值传递给片段的create实例方法,这显然是合乎逻辑的。
令人难以置信的

9

除了要意识到的以外,您还需要记住的不仅仅是启动的活动不会隐式破坏调用活动。当然,您可以对其进行设置,以便用户单击按钮进入页面,然后启动该页面的活动并销毁当前页面。这导致很多开销。我能给您的最佳指南是:

**仅在有意义的情况下才可以启动主活动并同时打开该活动(考虑多个窗口),才可以启动新活动。

当您需要进行多项活动时,Google云端硬盘就是一个很好的例子。主要活动提供了一个文件浏览器。打开文件后,将启动一个新活动来查看该文件。您可以按“最近使用的应用程序”按钮,这将使您无需关闭打开的文档即可返回浏览器,然后甚至可以并行打开第一个文档。


回覆 “仅在有意义的情况下启动一项新活动,并同时打开该活动(考虑多个窗口)。” 我不这么认为。使用片段 attach / detach方法可以很好地解决这种情况。
ToolmakerSteve

7

我所做的事情:尽可能减少碎片。不幸的是,几乎有可能这样。因此,我最终会遇到很多碎片和一些活动。我意识到的一些缺点:

  • ActionBar&菜单:当2个片段的标题,菜单不同时,
    将很难处理。例如:添加新片段时,您可以更改操作栏标题,但是从backstack无法还原旧标题。在这种情况下,您可能需要在每个片段中使用工具栏,但是请相信我,这将花费您更多的时间。
  • 当我们需要时startForResult,活动有但片段没有。
  • 默认情况下没有过渡动画

我的解决方案是使用活动片段包装在其中。因此,我们有单独的操作栏,菜单startActivityForResult,动画,...


1
非常有用的要点,谢谢。您能否阐明“ 包裹片段的活动 ”?您是否为每个片段进行了单独的活动?如果是这样,您是否根本需要Fragment?
ToolmakerSteve

3
有一种还原标题和内容的方法。用于getSupportFragmentManager().addOnBackStackChangedListener添加侦听器。在该侦听器中获取当前片段,然后设置标题和内容。
babay

4

fragment活动过度的一大优点是,用于片段的代码可以用于不同的活动。因此,它在应用程序开发中提供了代码的可重用性


3
怎么样?你能提供一些例子吗?
sofs1,2013年

1
@ sofs1您的问题没有多大意义。片段中的任何代码均保持不变,无论该片段从哪个活动被无效化。
令人难以置信的

@TheincredibleJan但是我们也不能说“一个活动中的任何代码都保持不变,无论从哪个活动实例化了第二个活动”。我看不出有什么区别。
iforce2d

3

使用每个应用为基础提供一种活性fragment 使用fragment用于屏幕, fragments精简版重量相比,activites 片段是可重复使用的 片段是更适合于应用程序,它同时支持电话和片剂


2

您可以自由使用其中之一。
基本上,您必须评估哪个是最适合您的应用的。考虑一下您将如何管理业务流程以及如何存储/管理数据首选项。

想一想,碎片如何存储垃圾数据。实现片段时,您有一个活动根以填充片段。因此,如果您尝试实施太多带有过多片段的活动,则必须考虑应用程序的性能,因为要操纵(粗略地说)两个上下文生命周期,请记住复杂性。

记住:我应该使用片段吗?我为什么不呢

问候。


1

我使用Fragments以获得更好的用户体验。例如,如果您有一个Button并想运行,例如,当您单击它时要运行一个Web服务,我会将一个Fragment附加到父Activity。

if (id == R.id.forecast) {

    ForecastFragment forecastFragment = new ForecastFragment();
    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.main_content, forecastFragment);
    ft.addToBackStack("backstack");
    forecastFragment.setArguments(b);
    ft.commit();
}

这样,用户将不必进行其他活动。

其次,我更喜欢Fragments,因为您可以在旋转期间轻松处理它们。


是什么使该示例具有更好的用户体验?他们将如何知道(或关心)他们正在做某项活动或某个片段?
iforce2d

1

这取决于您真正要构建的内容。例如,navigation drawer使用片段。标签也可以使用fragments。另一个好的实现是在的地方listview。旋转手机并单击一行时,活动将显示在屏幕的剩余一半。我个人使用fragmentsfragment dialogs,因为它更专业。另外,它们的旋转操作也更容易。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.