Android活动/片段负责数据加载

当为客户启动一个新的应用程序时,我再次问自己同样的问题:谁应该负责加载数据:活动或片段。 我已经采取了各种应用程序的两个选项,我想知道哪种模式是最好的根据你的方面:

  • 限制了代码的复杂性。
  • 处理边缘情况(如屏幕旋转,屏幕正在进行节电,连接丢失等)

选项1 – 活动加载数据和片段只显示它

这允许有刚刚喂入一堆对象的片段显示。 他们对加载数据以及我们如何加载数据一无所知。

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

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

选项2 – 活动安排片段和片段负责提取数据

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

活动只是在屏幕上安排片段的方式,并协调应用程序活动之间的转换。

Solutions Collecting From Web of "Android活动/片段负责数据加载"

理想情况下, ActivityUI都不应该包含任何“模型”逻辑 – 这些类应该是轻量级的,只负责UI逻辑。 但是当你决定创build一个单独的模型对象时,你有两难的select来初始化和存储这个对象,以及如何处理configuration的改变。 这里有一些方便的技巧:

您可以创build一个没有UI的 Fragment 模型 ,让它保留实例来处理configuration更改(这是AFAIK最简单的方法来保存configuration数据,而无需任何麻烦),并通过findFragmentById()其检索到。 你在里面做一切昂贵的操作(当然使用后台线程),存储你的数据,你就完成了。 有关更多信息,请参阅添加没有UI部分的片段 。

UPD :现在有更好的方法来处理configuration更改:来​​自Google架构组件的 ViewModel 。 这是一个很好的例子 。

从理论上说,如果它能工作,你可以做任何你想做的事情。 事实上,碎片和活动显示的数据和处理自己的生命周期。

由于片段属于活动,因此您必须联合使用才能更好地处理所有数据,但大多数情况下取决于您的需求。

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

如果您了解MVC – 模型视图控制器 – devise模式,那么您可以将“片段”视为“视图”,将“活动”视为模型。

当你用多个片段构build一个应用程序时,情况会变得更加有趣。

一些关键点是决定因素 –

  • 片段的想法是,它是一个可以被任何需要它的Activity使用的UI的包装块。 在此基础上,您必须问自己,是否必须处理的事件对于每个活动都是相同的或每个活动独有的。 如果它是相同的,那么事件处理程序最好写在碎片内。

  • 片段没有自己的用户界面 – 它通过与片段关联的活动显示。 事件由“活动”拥有的“查看”层次结构中的对象生成。 例如,如果您尝试使用Android Studio添加事件处理程序,则会将其添加到“活动”而不是“碎片”。

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

  • Fragment是一个实现onCreateView方法的类,用于提供一个可以由Activity显示的View层次结构。

  • 要在活动中使用片段,您必须使用FragmentManager和FragmentTransaction来添加片段。 您可以使用add方法添加Fragment,但在调用commit方法之前什么都不会发生。

  • 在使用提交的方法(通常是Activity的onCreate)终止CreateView事件后,将运行Fragment的onCreateView,并将Fragments View层次结构添加到Activity的内容中。

  • 你必须编写代码来保存和恢复Fragment可能具有的任何附加状态。

  • 如果一个任务对于碎片的所有实例是共同的,那么它的代码应该存在于碎片中。

  • 尤其是处理事件的代码可以在Fragment中定义。

  • 活动应该被用来托pipe处理由UI提供的数据的代码。

  • 将活动事件处理程序附加到Fragment的用户界面或难以正确执行。

  • 从情景决定你的应用程序将是什么。 它是服务,活动,小部件,甚至内容提供商还是复杂的系统,包括一些不同的组件。 根据情景testing您的决定。

  • 所有这些都必须在碎片被破坏和重新创build后才能工作。

    (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

    最难的部分是实现像事件机制。

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

  • 用他们所做的描述来制作用户界面组件列表(而不是如何)这些将在稍后成为小部件和活动或片段或布局。

  • 通常你会想要一个片段与另一个片段进行通信,例如根据用户事件来改变内容。 所有片段到片段的通信都是通过关联的活动完成的。 两个碎片不应该直接沟通。

  • 当你的应用程序是完全模块化的时候,碎片不会彼此了解。 您可以添加一个片段,删除一个片段,replace一个片段,并且它们都应该正常工作,因为它们都是独立的,并且活动可以完全控制configuration。

  • 除非您开始交易,否则您无法使用片段做任何事情。 在事务中,你可以设置你想要发生的事情,通常把碎片添加到当前的布局中,但是直到你使用commit方法,什么都不会发生。

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

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

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

但是,您可能会遇到这种情况,即重新启动应用程序和恢复大量数据可能代价高昂,从而导致糟糕的用户体验。 在这种情况下,你有两个select:

1) 在configuration更改期间保留一个对象

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

2) 自己处理configuration更改

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

我要做的就是pipe理活动中的所有数据stream( bluetooth, database storage, etc ),并仅使用片段来显示UI或处理用户input。

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

另外,如果数据stream在UI线程上很重要,可以考虑使用具有后台线程的Service 。 如果这是一次性的事情,你可以使用一个IntentService ,否则你可以实现一个Bind Service并从任何你有Context的地方请求绑定。

更多阅读 – 片段和活动 – 一起工作 。

我更喜欢并始终使用Option-1来实现Option-1。

不selectOption-1的原因:

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

  2. 一个活动可以加载任何数量的碎片,通常你最终会问自己这些问题, 在你的应用程序是高度可扩展的已经很大的情况下 。 将一个活动中的所有事件写出来并传递给fragment将是一个复杂的事情。

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

我举一个例子:你的应用程序有2个特征A和B.这2个特征是相互独立的。 而且每个function都有很多的屏幕。 您应该创build2个活动A和B,因为当使用活动A时,应该释放活动B以减less应用程序的内存。 同样的,当使用B时,A应该被释放。 上下文A和B的内存是独立的,如果要将数据从活动A发送到B,则必须在应用程序上下文中使用意图或使用全局variables。 意图由OSpipe理,而不是由应用程序pipe理。 当A向B发送意向时,如果A被销毁,意向发送给B就没有问题.Activity是App模块,它可以被其他应用程序调用(片段不可能)。

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