用于数据加载的 Android 活动/片段职责
Posted
技术标签:
【中文标题】用于数据加载的 Android 活动/片段职责【英文标题】:Android activity/fragment responsibilities for data loading 【发布时间】:2014-08-30 02:08:26 【问题描述】:在为客户启动新应用程序时,我再次问自己同样的问题,即谁应该负责加载数据:活动或片段。我对各种应用都采用了这两种选择,但我想知道哪种模式最适合您:
限制代码复杂度。 处理边缘情况(如屏幕旋转、屏幕节能、连接中断等)选项 1 - Activity 加载数据 & 片段只显示它
这允许有只喂一堆对象来显示的片段。他们对加载数据以及我们如何加载数据一无所知。
另一方面,活动使用所需的任何方法加载数据(例如,最初是最新的 50 个条目,然后在搜索时加载搜索结果)。然后它将它传递给显示它的片段。加载数据的方法可以是任何东西(来自服务,来自数据库,......片段只知道 POJO)
这是一种 MVC 架构,其中 Activity 是控制器,片段是视图。
选项 2 - Activity 安排片段 & 片段负责获取数据
在这种模式中,片段是应用程序的自治片段。他们知道如何加载他们正在显示的数据以及如何将其显示给用户。
Activity 只是一种在屏幕上排列片段和协调应用程序 Activity 之间转换的方法。
【问题讨论】:
我更喜欢选项 1,因为片段生命周期始终调用 onCreateView ,即使在恢复后也意味着再次加载数据。但是在一个活动中加载一次数据就可以很容易地在片段上呈现。而且fragment之间的数据传递也很容易实现。 我把视图特定的逻辑放在fragment上,把通用的逻辑放在activity上。 【参考方案1】:理论上你可以做任何你想做的事,如果它有效的话。 实际上,片段和活动显示数据并处理它们自己的生命周期。
由于片段属于活动,因此您必须将两者结合使用以更好地处理所有数据,但这主要取决于您的需求。
如果您牢记 Fragment 应该提供 UI 而 Activity 应该提供处理的想法,那么您就有了很好的关注点和代码划分,这应该允许 Fragment 或 Activity 被重用。
如果您了解MVC - 模型视图控制器 - 设计模式,那么您可以将片段视为视图,将活动视为模型。
当您构建一个包含多个 Fragment 的应用程序时,事情会变得更加有趣。
一些关键点作为决定因素 -
Fragment 的概念是它是一个封装好的 UI 块 任何需要它的 Activity 都可以使用它。在此基础上,您必须 问问自己必须处理的事件是否相同 每个活动或每个活动独有。如果相同,则 事件处理程序最好写在 Fragment 中。
片段没有自己的 UI - 它由 Fragment 关联的活动。事件是 由 View 层次结构中的对象生成,由 活动。如果您尝试使用 android Studio 添加事件处理程序, 例如,它会将其添加到 Activity 而不是 Fragment。
您可以定义要处理事件的EventListener
在 Fragment 中,然后将其连接到 View 中的对象
您要在其中生成事件的活动。
片段是一个实现onCreateView
方法的类
提供可由 Activity 显示的 View 层次结构。
要在 Activity 中使用 Fragment,您必须使用 FragmentManager 和一个 FragmentTransaction。您可以添加片段 使用 add 方法,但在调用提交之前什么都不会发生 方法。
在使用提交的方法之后,通常是 Activity 的 onCreate,终止 CreateView 事件运行 Fragment 的 onCreateView 和 Fragments View 层次结构被添加到 活动的内容。
您必须编写代码来保存和恢复任何附加状态 片段可能有。
如果一个任务对 Fragment 的所有实例都是通用的,那么它的代码 应该存在于 Fragment 中。
特别是处理事件的代码可以在 片段。
应使用 Activity 来托管处理数据的代码 由 UI 提供。
将 Activity 事件处理程序附加到 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 与另一个 Fragment 进行通信,例如 根据用户事件更改内容。所有片段到片段 通信是通过关联的 Activity 完成的。两个片段 永远不要直接交流。
当您的应用完全模块化时,片段并不知道每个片段 其他。您可以添加片段,删除片段,替换片段, 他们应该都可以正常工作,因为他们都是独立的,并且 Activity 可以完全控制配置。
除非您启动事务,否则您无法对 Fragment 执行任何操作。 在事务中,您可以设置您想要发生的事情, 通常将 Fragment 添加到当前布局中,但没有任何反应 直到你使用 commit 方法。
使用屏幕方向有效处理数据 -
当屏幕方向发生变化时,Android 会重新启动正在运行的 Activity(调用onDestroy()
,然后调用onCreate()
)。
要正确处理重启,您的 Activity 必须通过正常的 Activity 生命周期恢复其先前的状态,在该生命周期中,Android 在销毁您的 Activity 之前会调用 onSaveInstanceState()
,以便您可以保存有关应用程序状态的数据。然后您可以在onCreate()
或onRestoreInstanceState()
期间恢复状态。
但是,您可能会遇到这样一种情况,即重新启动应用程序和恢复大量数据的成本可能会很高,并且会造成糟糕的用户体验。在这种情况下,您还有另外两个选择:
1) 在配置更改期间保留对象
允许您的活动在配置更改时重新启动,但将有状态的对象携带到您的活动的新实例。
2) 自行处理配置更改
防止系统在某些配置更改期间重新启动您的 Activity,但在配置发生更改时接收回调,以便您可以根据需要手动更新您的 Activity。
我要做的是管理所有数据流 (bluetooth, database storage, etc
)
在 Activity 中使用 Fragments 仅用于 UI 显示或处理用户输入。
这种方式更容易处理配置更改/屏幕旋转。
另外,如果 UI 线程上的数据流很繁重,请考虑使用带有后台线程的 Service
。
如果是“一次性”的事情,可以使用IntentService
,
否则,您可以实现 Bind Service
并从您拥有 Context 的任何地方请求绑定。
更多阅读 - fragment-and-activity-working-together。
【讨论】:
【参考方案2】:理想情况下,Activity
和 Fragment
with UI 都不应包含任何“模型”逻辑 - 这些类应该是轻量级的并且只负责 UI 逻辑。但是当您决定创建一个单独的模型对象时,您将面临选择在哪里初始化和存储该对象以及如何处理配置更改的困境。这里有一些方便的技巧:
您可以创建一个 模型 Fragment
无需 UI,使其 retain instance 处理配置更改(这是 AFAIK 跨配置保存数据的最简单方法。更改没有麻烦)并通过findFragmentById()
在任何您需要的地方检索它。您在其中进行一次所有昂贵的操作(当然使用后台线程),存储您的数据,您就完成了。
有关详细信息,请参阅Adding a fragment without a UI 部分。
UPD:现在有更好的方法来处理配置更改:ViewModel 来自 Google's Architecture Components。这是a good example。
【讨论】:
这就是我最终的做法。提供了一个非常明确的区分谁做什么。使用 Otto 库(或您喜欢的任何事件总线库)有助于在通过事件总线进行通信时保持一切分离。感谢您的意见。【参考方案3】:我更喜欢并且总是实现 Option-2 而不是 Option-1。
不选择 Option-1 的原因:
我们应该为 Fragments 中触发的事件设置监听器,并将其传递回 Activity 以加载数据、处理数据并将其推送回 Fragment,这会使工作变得更加复杂。
一个 Activty 可以加载任意数量的 Fragment,通常您会在 您的应用具有高度可扩展性和 的场景中向自己提出这些问题 >已经很大了。在一个活动中编写所有事件并将其传递给片段将是一个复杂的过程。
正如@Ved Prakash 提到的,如果方向由 Activty 处理,则处理屏幕方向会变得复杂。
【讨论】:
我有一个带有片段框架布局和一个静态类别警报对话框按钮的活动。默认情况下,使用片段在该框架布局上加载一个类别的数据。如果用户在类别上选择新类别按钮将该值传递给服务器并获取响应,我还需要使用现有片段填充相同的框架布局的最新响应。请根据所选项目使用动态数据为一个片段提供一些建议。【参考方案4】:我有一个例子: 您的应用程序有 2 个功能 A 和 B。这 2 个功能彼此独立。每个功能都有很多屏幕。 您应该创建 2 个活动 A 和 B,因为当使用 Activity A 时,应释放 Activity B 以减少应用程序的内存。使用 B 时也一样,应该释放 A。 Context A 和 B 的内存是独立的,如果要从 Activity A 向 B 发送数据,则必须使用 Intent 或在 Application Context 中使用全局变量。意图由操作系统管理,而不是由应用程序管理。当A向B发送intent时,如果A被destroy则intent发送给B没有问题。Activity是App模块,可以被其他应用调用(fragment是不可能的)。
例如:特征 A 有很多屏幕(例如:Fragment1、Fragment2)。它们使用相同的数据并相互依赖。每个屏幕都应该是一个片段。当处理数据时,您可以通过调用函数 getActivity() 来获取对数据的引用,然后获取对 Activity 上下文(或 Activity 内存)变量的引用来写入或读取它。 Fragment1 和 Fragment2 属于 Activity A Context。也就是说,Fragment 1 和 Fragment 2 可以通过 Activity 上下文的变量相互传递数据,很容易做到。注意到 Intent 是由 OS 管理的,通过 Intent 发送数据非常昂贵。
【讨论】:
以上是关于用于数据加载的 Android 活动/片段职责的主要内容,如果未能解决你的问题,请参考以下文章