Android活动/片段负责数据加载
当为客户启动一个新的应用程序时,我再次问自己同样的问题:谁应该负责加载数据:活动或片段。 我已经采取了各种应用程序的两个选项,我想知道哪种模式是最好的根据你的方面:
选项1 - 活动加载数据和片段仅显示它
这允许有刚被馈送一堆对象显示的片段。 他们对加载数据以及我们如何加载数据一无所知。
另一方面,活动使用需要的任何方法加载数据(例如最初最近的50个条目以及搜索时加载搜索结果)。 然后它将它传递给显示它的片段。 加载数据的方法可以是任何东西(来自服务,来自数据库,......碎片只知道POJO)
这是一种MVC架构,其中活动是控制器,碎片是视图。
选项2 - 活动安排片段和片段负责获取数据
在这种模式中,片段是自治的应用程序片段。 他们知道如何加载他们正在显示的数据以及如何显示给用户。
活动只是在屏幕上安排片段和协调应用程序活动之间转换的一种方式。
理想情况下, Activity
和带UI的 Fragment
都不应包含任何“模型”逻辑 - 这些类应该是轻量级的,仅对UI逻辑负责。 但是当你决定创建一个单独的模型对象时,你有两难的选择来初始化和存储这个对象以及如何处理配置更改。 这里有一些方便的技巧:
您可以创建一个没有UI的 Fragment
模型 ,让它保留实例来处理配置更改(它是AFAIK最简单的方法,可以在不改变配置的情况下保存数据),并通过findFragmentById()
其检索到。 你可以在其中完成所有昂贵的操作(当然是使用后台线程),存储数据并完成。 有关更多信息,请参阅添加没有UI部分的片段。
UPD :现在有更好的方法来处理配置更改:来自Google体系结构组件的ViewModel。 这是一个很好的例子。
从理论上讲,如果它能够工作,你可以做任何你想做的事。 事实上,碎片和活动显示数据并处理他们自己的生命周期。
由于片段属于活动,因此您必须联合使用以更好地处理所有数据,但大多数情况下取决于您的需求。
如果你记住Fragment应该提供UI并且Activity应该提供处理的想法,那么你就可以很好地划分关注点和代码,这些应该允许Fragment或Activity被重用。
如果您了解MVC - 模型视图控制器 - 设计模式,那么您可以将Fragment视为视图,将活动视为模型。
当您使用多个碎片构建应用程序时,情况会变得更加有趣。
一些关键点是决定因素 -
片段的想法是,它是一个可以被任何需要它的活动使用的用户界面。 在此基础上,您必须问自己,必须处理的事件是否与每个活动相同或每个活动独有。 如果它是相同的,那么事件处理程序最好写在片段中。
片段没有自己的用户界面 - 它通过片段关联的活动显示。 这些事件由View层次结构中的对象生成,该层次由Activity所拥有。 例如,如果您尝试使用Android Studio添加事件处理程序,则会将其添加到“活动”而不是“碎片”。
您可以在Fragment中定义要处理事件的EventListener
,然后将其挂接到要在其中生成事件的Activity中的View对象。
Fragment是一个实现onCreateView
方法的类,用于提供可以由Activity显示的View层次结构。
要在Activity中使用Fragment,您必须使用FragmentManager和FragmentTransaction来添加它。 您可以使用add方法添加Fragment,但在调用commit方法之前什么也没有发生。
在使用提交的方法(通常是Activity的onCreate)终止CreateView事件后,将运行Fragment的onCreateView,并将Fragments View层次结构添加到Activity的内容中。
您必须编写代码来保存和恢复Fragment可能具有的任何其他状态。
如果一项任务对碎片的所有实例都是共同的,那么它的代码应该存在于碎片中。
特别是处理事件的代码可以在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
最难的部分是实现类似事件机制的东西。
在复杂系统的情况下,在应用程序组件之间分配功能和数据实体。 列出组件和它们是什么(活动或其他)。
用他们所做的描述来制作用户界面组件列表(而不是如何)这些将在稍后成为小部件和活动或片段或布局。
通常你会希望一个片段与另一个片段进行通信,例如根据用户事件更改内容。 所有片段到片段的通信都是通过关联的活动完成的。 两个碎片不应该直接通信。
当你的应用程序是完全模块化的,碎片不会彼此了解。 您可以添加一个片段,删除一个片段,替换一个片段,并且它们应该都可以正常工作,因为它们都是独立的,并且该活动可完全控制配置。
除非您开始交易,否则您无法使用片段做任何事情。 在事务中,您可以设置想要发生的事情,通常将碎片添加到当前布局,但在使用commit方法之前不会发生任何事情。
使用屏幕方向高效处理数据 -
当屏幕方向改变时,Android重新启动正在运行的Activity( onDestroy()
被调用,接着是onCreate()
)。
要正确处理重新启动,重要的是您的活动通过正常的Activity生命周期恢复其以前的状态,在该生命周期中Android会在销毁活动之前调用onSaveInstanceState()
,以便保存有关应用程序状态的数据。 然后可以在onCreate()
或onRestoreInstanceState()
期间恢复状态。
但是,您可能会遇到这种情况:重新启动应用程序和恢复大量数据可能代价高昂,并且会造成糟糕的用户体验。 在这种情况下,你有两个选择:
1) 在配置更改期间保留一个对象
允许您的活动在配置更改时重新启动,但将有状态对象带入活动的新实例。
2) 自己处理配置更改
防止系统在某些配置更改期间重新启动您的活动,但在配置发生更改时收到回叫,以便您可以根据需要手动更新活动。
我要做的就是管理活动中的所有数据流( bluetooth, database storage, etc
),并仅将碎片用于UI显示或处理用户输入。
这种方式更容易处理配置更改/屏幕旋转。
另外,如果数据流很重要在UI线程上,请考虑使用具有后台线程的Service
。 如果这是一次性的事情,你可以使用一个IntentService
,否则你可以实现一个Bind Service
并从任何你有上下文的地方请求绑定。
更多阅读 - 片段和活动 - 一起工作。
我更喜欢并始终使用Option-1而不是Option-1。
不选择Option-1的原因:
我们应该让侦听器在Fragments中触发事件,并将其传递给活动以加载数据,处理数据并将其推回片段,这会使工作更加复杂。
一个Activty可以加载任意数量的碎片,通常你最终会在你的应用具有高度可扩展性并且已经很庞大的情况下,自问自问。 将所有事件写入活动并将其传递给片段将是一个复杂的过程。
正如@Ved Prakash所提到的,如果方向由Activty处理,处理屏幕方向将变得复杂。
上一篇: Android activity/fragment responsibilities for data loading