MVVM 架构,ViewModel 和LiveData 第一部分(译)

img

原文:MVVM architecture, ViewModel and LiveData (Part 1)

在Google I / O期间,Google推出了包含LiveDataViewModelarchitecture components ,这有助于使用MVVM模式开发Android应用程序。 本文讨论这些组件如何为遵循MVVM的Android应用程序提供服务。

快速定义MVVM

如果您熟悉MVVM,则可以完全跳过本节。

MVVM是增强关注点分离的体系结构模式之一,它允许将用户界面逻辑从业务(或后端)逻辑中分离出来。 它的目标(与其他MVC模式目标一致)是为了实现以下原则:“使UI代码简单且不含应用程序逻辑,以便更易于管理”。

MVVM主要有以下几个层次:

  • Model

    Model表示应用程序的数据和业务逻辑。 这一层的推荐实施策略之一是通过观测数据并且公开其数据,从而完全从ViewModel或任何其他观察者/消费者(这将在我们的MVVM示例应用程序中进行说明)进行解耦。

  • ViewModel

    ViewModel与Model交互,并且还准备可以被View观察的observable(s)。 ViewModel可以选择性地为View提供钩子(hooks)以将事件传递给Model。

    该层的一个重要实现策略是将其与View分离,即ViewModel不应该意识到与之交互的View。

  • View

    最后,此模式中的View是观察(或订阅)ViewModel,可观察数据以获取数据并且相应地更新UI元素。

下图显示了MVVM组件和基本交互。

MVVM组件和基本交互

LiveData

如上所述,LiveData是新引入的体系结构组件之一。 LiveData是一个可观察的数据持有者。 这允许应用程序中的组件能够观察LiveData对象的更改,而无需在它们之间创建明确的和严格的依赖关系路径。 这将完全分离LiveData对象使用者的LiveData对象生产者。

除此之外,LiveData也有很大的好处,LiveData尊重应用程序组件(活动,片段,服务)的生命周期状态,并处理对象生命周期管理,确保LiveData对象不泄漏。

根据Google文档,如果您已经在使用Rx或Agera等Library,则可以继续使用它们而不是LiveData。 但在这种情况下,您有责任处理每个Android组件生命周期的对象分配和解除分配。

由于LiveData尊重Android生命周期,这意味着除非LiveData主机(activity或fragment)处于活动状态(接收onStart()但未收到onStop()),否则它将不会调用其观察者回调。 除此之外,当主机收到onDestroy()时,LiveData也会自动删除观察者。

LiveData将在下面的MVVM示例应用程序中进行说明。

ViewModel

ViewModel也是新引入的体系结构组件之一。 architecture components 提供了一个名为ViewModel的新类,它负责为UI / View准备数据。

ViewModel为您的MVVM ViewModel层提供了一个很好的基类,因为ViewModel(及其子类AndroidViewModel)的扩展类在配置更改期间自动保留其保留数据。 这意味着,在配置更改后,此ViewModel所有数据立即可用于下一个Activity或Fragment实例。

下图显示了ViewModel组件的生命周期。

ViewModel组件的生命周期

ViewModel也将在我们的MVVM示例应用程序中进行说明。

示例应用程序

现在,让我们来看看最有趣的部分,让我们把所有这些东西放在一个示例应用程序中。 此MVVM示例应用程序主要包含两个屏幕。 下面显示的第一个屏幕显示了Google GitHub项目列表,其中包含一些简要信息,例如标题,编程语言和最终观察者数量。

Project List

一旦应用程序的最终用户触摸任何列表项、GitHub项目的详细信息,屏幕将显示项目描述、编程语言、观察者数量、公开问题、创建和上次更新日期,最后显示克隆URL。

Project Details

示例应用程序交互图

下图显示了示例应用程序的包结构

示例应用程序的包结构

以下交互图显示了检索Google GitHub项目的应用场景之一的示例交互图。

Google GitHub项目的应用场景

如图所示,每个图层都从其后续图层(Fragment(View) - > ViewModel - > Repository)观察LiveData,最后一旦检索到项目列表,就会使用RecyclerView适配器绑定显示项目列表。

Repository模块负责处理数据操作。 通过确保这一点,Repository模块可以为应用程序的其余部分提供干净的API,并简化使用者ViewModel的工作。 如果需要更新数据,系统信息库模块应该知道从哪里获取数据以及进行哪些API调用。 它们可以被视为不同数据源(REST服务,数据库,XML文件等)之间的中介。

现在,让我们从下往上解释这些图层,从Model,ViewModel开始,最后用View来检索GitHub项目场景。

示例应用程序模型层

让我们从业务逻辑层开始,我们有两个模型对象

  • Project,包含GitHub项目的信息,如id,名称,描述,创建日期等等。
  • 用户,包含GitHub项目所有者的用户信息。

为了与GitHub RESTful API进行交互,我使用了我喜欢的Retrofit 2来定义存储库包中的以下简单接口。

为了便于ViewModel的Job,创建一个ProjectRepository类来与GitHub服务交互,并最终为ViewModel提供一个LiveData对象。 它也将在以后用于编排服务呼叫。 以下代码片段显示了getProjectList()API实现。

ProjectRepository是ViewModel的数据提供者,它具有getProjectList(),它将响应简单地包装到LiveData Object中。

为了简化本文的目的,错误处理被省略,并且将在下一篇文章中进行说明。

示例应用程序ViewModel图层

为了消费getProjectList()API,创建了ViewModel类(调用Repository API并可以为LiveData执行任何所需的转换)。 以下代码片段显示了ProjectListViewModel类。

如上所示,我们的ProjectListViewModel类扩展了AndroidViewModel,并在构造函数中调用getProjectList(“Google”)来检索Google GitHub项目。

在现实世界的情况下,在将结果数据传递给观察视图之前可能需要进行转换,为了进行转换,可以使用Transformation类,如下面的文档所示:

https://developer.android.com/topic/libraries/architecture/livedata.html#transformations_of_livedata

示例应用视图图层

最后,让我们快速浏览一下这个应用程序的视图层,我们主要有一个名为MainActivity的Activity,它负责处理代表应用程序视图的两个片段的导航:

  • ProjectListFragment,它显示Google GitHub项目的列表。
  • ProjectFragment,它显示所选的GitHub项目细节。

由于Activities和Fragments被视为生命周期所有者,活动需要扩展LifecycleActivity,片段需要扩展LifecycleFragment。 但是,请务必记住LifecycleActivity和LifecycleFragment类都是临时实现,直到Lifecycle与支持库集成为止:https://developer.android.com/reference/android/arch/lifecycle/LifecycleActivity.html

现在,让我们继续我们的项目检索方案,查看ProjectListFragment,下面的代码片段显示了最重要的集成部分。

如上所示,ProjectListFragment获取ProjectListViewModel,然后监听其getProjectListObservable()方法,以便在准备好时获取Github项目列表。 最后,一旦检索到项目列表,它将被传递给projectAdapter(RecyclerView适配器),以显示RecyclerView组件中的项目列表。

这是对项目的一个端到端场景的解释,您可以在这里找到GitHub中提供的完整项目:

https://github.com/hazems/mvvm-sample-app/tree/part1

MVVM实施的重要指导原则

现在,重点介绍MVVM实现的一些重要指导原则:

  • 如示例中所示,ViewModels不会直接引用Views,因为如果这样做,ViewModels可能会超出View的生命周期,并且可能会发生内存泄漏。
  • 建议使用Model和ViewModel使用LiveData公开其数据,因为LiveData尊重应用程序组件(活动,片段,服务)的生命周期状态,并处理确保LiveData对象不泄漏的对象生命周期管理。

下一篇文章

故事尚未完成,因为有些事情需要处理,比如:

  • 依赖注入
  • 错误处理
  • 缓存
  • 在此演示中添加更多功能以查看Room如何促进SQLite数据操作
  • 单元测试
  • 其他…

这将在MVVM的下一系列文章中进行说明,敬请关注。