用于数据加载的Android活动/片段职责

时间:2014-07-09 06:51:53

标签: android

当为客户启动一个新的应用程序时,我再问自己一个关于谁应该负责加载数据的问题:活动或片段。我已经为各种应用程序采取了两种选择,我想知道哪种模式最适合您:

  • 限制代码复杂性。
  • 处理边缘情况(如屏幕旋转,屏幕省电,连接丢失等)

选项1 - 活动加载数据&片段只显示它

这允许具有仅被馈送一堆对象的片段来显示。他们对加载数据以及我们如何加载数据一无所知。

另一方面,活动使用任何需要的方法加载数据(例如,最初的最近50个条目和搜索,加载搜索结果)。然后它将它传递给显示它的片段。加载数据的方法可以是任何东西(来自服务,来自DB,......片段只知道POJO)

这是一种MVC架构,其中活动是控制器,片段是视图。

选项2 - 活动安排片段&片段负责获取数据

在这种模式中,片段是应用程序的自主部分。他们知道如何加载他们正在显示的数据以及如何向用户显示它。

活动只是一种在屏幕上排列片段并协调应用程序活动之间转换的方法。

4 个答案:

答案 0 :(得分:17)

理论上,如果它有效,你可以做任何你想做的事。 实际上,片段和活动会显示数据并处理自己的生命周期。

由于片段属于活动,因此您必须同时使用两者来更好地处理所有数据,但这主要取决于您的需求。

如果你记住Fragment应该提供UI并且Activity应该提供处理的想法那么你就可以很好地划分关注点和代码,这样可以重用Fragment或Activity。

如果您了解 MVC - 模型视图控制器 - 设计模式,那么您可以将片段视为视图,将活动视为模型。

当您使用多个片段构建应用程序时,事情变得更加有趣。

一些关键点作为决定因素 -

  • 片段的想法是它是一个被包裹的UI块 可以被任何需要它的Activity使用。在此基础上你必须 问问自己,必须处理的事件是否相同 每个活动或每个活动的唯一活动。如果它是相同的那么 事件处理程序最好在Fragment中编写。

  • Fragment没有自己的用户界面 - 它显示为 片段与之关联的活动。事件是 由View层次结构中的对象生成,该层次结构由 活动。如果您尝试使用Android Studio添加事件处理程序, 例如,它会将它添加到Activity而不是Fragment。

  • 您可以定义要处理事件的EventListener 在Fragment中然后将它连接到View中的View对象 您要在其中生成活动的活动。

  • Fragment是一个实现onCreateView方法的类 提供可由活动显示的视图层次结构。

  • 要在活动中使用片段,您必须使用a添加它 FragmentManager和FragmentTransaction。您可以添加片段 使用add方法但在调用commit之前没有任何反应 方法

  • 在使用提交的方法之后,通常是Activity&#39 onCreate,终止CreateView事件运行Fragment' s onCreateView和Fragments View层次结构被添加到 活动的内容。

  • 您必须编写代码来保存和恢复任何其他状态 片段可能有。

  • 如果任务对Fragment的所有实例都是通用的,那么它的代码 应该生活在片段中。

  • 特别是处理事件的代码可以在 片段。

  • 应该使用Activity来托管处理数据的代码 由UI提供。

  • 将活动事件处理程序附加到Fragment的UI或是 很难做到正确。

  • 从方案中决定您的应用将是什么。是服务, 活动,小部件,甚至内容提供商或复杂系统, 包括一些不同的组件。测试你的决定 场景。

  • 所有这些都必须在Fragment被破坏后才能工作 重新创建。

    (1)Initialization of the Fragment,(2)Saving and restoring the Fragment's state和(3)Implementing something like an event mechanism so the Fragment can get the Activity's attention

    最难实​​现的是实现类似事件机制的东西。

  • 在复杂系统的情况下,分配功能和 应用程序组件中的数据实体列出组件 他们是什么(活动或其他)。

  • 制作带有描述的UI组件列表(不是如此) 然而,这些将是小部件和活动或片段或布局 后面。

  • 例如,通常您会希望一个片段与另一个片段进行通信 根据用户事件更改内容。所有片段到片段 通过相关的活动完成沟通。两片碎片 不应该直接沟通。

  • 当您的应用程序完全模块化时,片段并不知道每个应用程序 其他。你可以添加片段,删除片段,替换片段, 他们都应该工作得很好,因为他们都是独立的,而且 活动可以完全控制配置。

  • 除非您开始交易,否则您无法对片段执行任何操作。 在交易中,您可以设置您想要发生的事情, 通常将Fragment添加到当前布局,但没有任何反应 直到你使用提交方法。

使用屏幕方向高效处理数据 -

当屏幕方向发生变化时,Android会重新启动正在运行的活动(onDestroy()被调用,然后是onCreate())。

要正确处理重新启动,您的活动必须通过正常的活动生命周期恢复其先前的状态,在此生命周期中Android会在销毁活动之前调用onSaveInstanceState(),以便您可以保存有关应用程序状态的数据。然后,您可以在onCreate()onRestoreInstanceState()期间恢复状态。

但是,您可能会遇到这样一种情况:重新启动应用程序并恢复大量数据可能成本高昂,并且会导致糟糕的用户体验。在这种情况下,您还有两个选择:

1) 在配置更改期间保留对象

允许您的活动在配置更改时重新启动,但会将有状态的对象带到您的活动的新实例。

2) 自行处理配置更改

防止系统在某些配置更改期间重新启动您的活动,但在配置更改时收到回调,以便您可以根据需要手动更新活动。

我要做的是管理所有数据流(bluetooth, database storage, etc) 在活动和使用片段仅用于UI显示或处理用户输入。

这种方式更容易处理配置更改/屏幕旋转。

此外,如果数据流在UI线程上很重要,请考虑使用带有后台线程的Service。 如果它是一次拍摄"事情,你可以使用IntentService, 否则你可以实现Bind Service并从你拥有Context的任何地方请求绑定。

更多阅读 - fragment-and-activity-working-together

答案 1 :(得分:13)

理想情况下,带有的ActivityFragment 都不应包含任何"模型"逻辑 - 这些类应该是轻量级的,并且只负责UI逻辑。但是,当您决定制作单独的模型对象时,您可能会选择初始化和存储此对象的位置以及如何处理配置更改。这里有一些方便的技巧:

您可以创建模型 Fragment 无需用户界面,让它retain instance来处理配置更改(它的AFAIK是最简单的方法是跨配置保存数据。更改没有麻烦)并通过findFragmentById()在任何需要的地方检索它。你在其中进行一次所有昂贵的操作(当然是使用后台线程),存储你的数据并且你已经完成了。 有关详细信息,请参阅Adding a fragment without a UI部分。

UPD :现在有更好的方式来处理配置更改:来​​自ViewModelGoogle's Architecture Components。这是a good example

答案 2 :(得分:2)

我更喜欢并且总是在Option-1上实施Option-2。

未选择选项-1的原因:

  1. 我们应该拥有在Fragments中触发的事件的监听器,并将其传递回活动以加载数据,处理数据并将其推回到片段,这会使工作变得更加复杂。

  2. Activty可以加载任意数量的片段,通常情况下,您最终会在自己的应用具有高度可扩展性中向自己提问 >已经很大了。在活动中编写所有事件并将其传递给片段将是一个复杂的过程。

  3. 正如@Ved Prakash所提到的,如果方向由Activty处理,处理屏幕方向会变得复杂。

答案 3 :(得分:0)

我有一个例子: 您的应用程序有2个功能A和B.这两个功能相互独立。每个功能都有很多屏幕。 你应该创建2个活动A和B,因为当使用活动A时,应该释放活动B以减少应用程序的内存。当使用B时,A应该被释放。上下文A和B的内存是独立的,如果要将数据从活动A发送到B,则必须使用intent或在Application Context中使用全局变量。 intent由OS管理,而不是由应用程序管理。当A向B发送意图时,如果A是销毁是没有问题,意图发送到B.活动是App模块,它可以被其他应用程序调用(片段是不可能的)。

例如:功能A有很多屏幕(例如:Fragment1,Fragment2)。他们使用相同的数据并相互依赖。每个屏幕应该是一个片段。当使用数据进行处理时,您可以通过调用函数getActivity()来获取对数据的引用,然后引用Activity上下文(或Activity内存)的变量来写入或读取它。 Fragment1和Fragment2属于Activity A Context.it意味着Fragment 1和Fragment 2可以通过Activity上下文的变量相互传递数据,这很容易做到。注意到Intent是由OS管理的,当通过Intent发送数据时它非常昂贵。