英文原文链接:

https://google-developer-training.github.io/android-developer-advanced-course-concepts/unit-6-working-with-architecture-components/lesson-14-architecture-components/14-1-c-architecture-components/14-1-c-architecture-components.html

内容:

  1. Android架构组件是什么?
  2. 推荐的架构组件
  3. App架构示例
  4. Gradle构建文件
  5. 实体Entity
  6. DAO(数据访问对象)
  7. LiveData
  8. Room数据库
  9. Repository
  10. ViewModel
  11. Displaying LiveData
  12. Lifecycle-aware components
  13. 分页库(Paging libreary)
  14. 总结
  15. 相关实践
  16. 学习更多

Android组件库是什么?

Android操作系统积极管理资源,以在大量设备上运行良好,有时这使得构建健壮的应用具有挑战性。Android架构组件提供了关于应用架构的指导,包括用于生命周期管理和数据持久性等常见任务的库。

架构组件帮助你以一种健壮、可测试、稳定的方式来构建应用,使用更少的样板代码。架构组件提供了一种简单、灵活和实用的方法,将你从常见的问题中解脱出来,以便你可以专注于构建出色的体验。

推荐的架构组件

为了介绍术语,这里简要介绍架构组件以及它们是如何一起工作的。每一个架构组件在后续章节中都有详细介绍。这张图显示了该架构的基本形式。

Entity:当使用架构组件时,实体是描述数据表表的带注释的类。

SQLite database:在该设备,数据被存储在SQLite数据表。简单起见,其他的存储选项,美丽如web服务,在本章中省略了。Room持久性库为你创建并维护这个数据库。

DAO:数据访问对象。SQL查询到函数的映射。过去,必须在helper类(如SQLiteOpenHelper)中定义这些查询。当你使用DAO,你调用这些方法,组件会负责其余的事情。

Room database:数据库层位于SQLite数据库之上,负责处理日程任务,这些任务通常是用helper类来处理的,比如SQLiteOpenHelper。提供更简单的本地数据库存储。Room数据库使用DAO向SQLite数据库发出查询。

Respository:为管理多个数据源而创建的类,例如使用WordRepository类。

ViewModel:向UI提供数据并充当Repository和UI之间的通信中心。从UI中隐藏后端。ViewMdel实例在设备配置更改后仍然存在。

LiveData:遵循观察者模式的数据持有者类,意味着它可以被观察。总是保存/缓存最新版本的数据。当数据发生改变时,通知它的观察者。LiveData具有生命周期意识。UI组件观察相关数据。LiveData自动管理停止和恢复观察,意味它知道相关生命周期状态的变化。

App架构示例

下图显示了和上图一样的基本架构形式。但是在后面的章节会深入到每个架构组件。

Gradle文件

为了使用架构组件库,你必须手动添加最新版本库到你的gradle文件中。

添加以下代码到你的build.gradle(Module:app)文件,在依赖块的末尾:

从添加组件到你的项目中获取当前的版本号。在你的build.gradle(Project:RoomWordsSample)文件,添加版本号到文件的末尾,如下代码所示:

Entity

带有数据库的应用程序的数据以存储在数据库中的数据为中心。当然这里会有不同来源的其他数据,但简单起见,在这里会忽略其他数据。

Room模型一个SQLite数据库,被一个SQLite数据库所实现。SQLite将数据库存储在行和列的表中。每一行代表一个实体(或者记录),每一列标识该实体中的一个值。例如,字典条目的实体可能包含唯一ID,单词,定义和语法信息,以及纸箱更多信息的链接。

另一个常见的实体是一个人,具有唯一的ID、名、姓、电子邮件和人口信息。这样的数据库中的实体可能如下所示:

学习更多SQLite数据库知识,参见Android开发者基础课程中的SQLite入门。

当你使用架构组件(或SQLite数据库)编写应用程序时,你可以在类中定义实体。类的每个实例代表一行,每一列代表一个成员变量。

下面时代表Person的实体:

Entity注解

对于和entity一起工作的Room,你需要提供Room信息,将实体的java类的内容(例如Person)与你想在数据库中标识的内容联系起来。你可以使用注解来实现这一点。

下面是一些常用的注解:

  1. @Entity(tableName ="word_table")每一个@Entity实例代表表中的一个实体。注解类声明,向Room表明该类是一个实体。如果希望表的名称和类的名称不一样,请指定表的名称。
  2. @primaryKey每一个实体需要一个主键。为每一个实体自动产生一个唯一key。使用autoGenerate=true添加和注释一个主整数键,如以下代码所示。
  3. @NonNull 表明一个参数,字段方法返回值不回为null。主键应该总是使用@NonNull注解。对于行中的强制字段使用此注解。
  4. @ColumnInfo(name ="word")指定数据库表中列的名称,如果你想列的民初和成员变量名称不一样。
  5. 存储在数据库中的每一个字段必须是public或者有getter方法,这样Room才可以访问它。下面的代码提供了一个get方法而不是直接暴露它们。

下面是标识Person实体的注释代码:

你可以使用注解定义实体之间的关系。有关详细和完整的注释列表,请参见Room包摘要参考。

The DAO(数据访问对象)

使用Room持久化库来访问你的app数据,需要使用数据访问对象或者DAOs。一组Dao对象(Dao)形成了Room数据库的主要组件。每个DAO包含提供应用程序数据库抽象访问的方法。

你可以注解DAO,以指定SQL查询并将它们与方法调用关联起来。编译器检查SQL中的错误,然后从注释生成查询。对于常见的查询,库提供了方便的注释,如@Insert,@Delete和@Update。

注意:

  1. DAO必须是接口或者抽象类。
  2. Room使用DAO为您的代码创建一个干净的API。
  3. 默认,查询(@query)必须在主线程意外的线程上执行。对于插入或删除操作,如果使用适当的注释,Room将为你负责线程管理。
  4. 当你要求Room插入数据库已经存在的实体时,默认操作是终止。你可以指定一个不同的冲突策略,例如替换。

下面代码演示了使用不同类型查询的注释:

LiveData

当你的APP以其他的方式显示数据或者使用数据,当数据发生变化时,你通常需要采取动作。这意味找你必须要观察数据以便当它发生改变时,你可以作出反应。根据数据的存储方式,该问题可能会很棘手。通过观察应用中多个组件的数据变化,可以在组件之间创建显示的、严格的依赖路径。这使得测试和调试变得非常困难。

为了避免这些问题,使用LiveData,一个用于数据观察的生命周期库类。如果你在方法描述中使用了LiveData类型返回值,大概数据库更新时,Room生成更新LiveData所需的所有代码。

使用LiveData的好处

确保你的UI匹配你的数据状态

LiveData遵循观察者模式,因此当生命周期状态发生改变时,它会通知观察对象。你可以整合代码更新使用这些观察对象的UI。你的app数据每次发生变化,不用去更新UI,你的观察者会在每次状态发生改变时更新UI。

不会有内存泄漏

观察者绑定到生命周期对象,当关联的生命周期被销毁时,观察者会在自己之后进行清理。

没有由于停止视图而导致的奔溃

如果观察者的生命周期是非活动的,就像back stack中的activity一样,那么它就不会接收到任何LiveData事件。

没有更多的手动生命周期处理

UI组件值观察相关数据,不停止或恢复观察。LiveData在观察过程中会意识到相关的生命周期状态变化,因此LiveData会自动的管理停止和恢复观察。

数据总是最新的

如果生命周期变为非活动状态,它将在再次激活时接收最新的数据。例如在后台的activity在它切到前台后,会收到最新的数据。

配置更改正确处理

如果一个activity或者fragment由于配置更改重新创建,例如设备旋转,该activity和fragment会立刻收到最新可用的数据。

资源可以共享

你可以使用单例模式扩展LiveData对象,例如为服务或者数据库执行此操作。LiveData对象连接到系统服务一次,然后任何需要资源的观察者都可以只监视LiveData对象。

使用LiveData

安装以下步骤来操作LiveData对象:

  1. 创建一个LiveData实例来保存特定类型的数据。这通常是在ViewModel类中完成。
  2. 创建一个定义了onChanged()方法的观察者对象,该方法控制当LiveData对象所持有的数据发生变化时发生什么。你通常在UI控制器(例如activity和fragment)创建一个观察者。
  3. 使用observer()方法将观察者对象附加到LiveData对象上。Oberserve()方法接受一个lifecycleOwner对象。它将Observer对象订阅到LiveData对象,以便在发生变化时通知观察者。通常将Observer对象附加到UI控制器中,例如activity和fragment。

提示:你可以使用observerForever(Observer)方法来注册一个没有关联LifecycleOwner对象的观察者。在这种情况下,观察者被认为总是处于活动状态,因此总是受到关于修改的通知。要删除这些观察者,调用removeObserver(Observer)方法。

当你更新存储在LiveData对象中的值时,所有注册的观察者都会被通知,并采取指定的措施,例如更新UI,只要附加的LifecyclerOwner处于活动状态。

LiveData允许UI控制器观察者订阅更新。当被LiveData对象所持有的数据发生变化,作为响应,UI会自动进行更新。

这些步骤会在接下来的章节中进行详细介绍。

使用LiveData使数据可观察

使数据可观察,使用LiveData进行包装就好。

对于Person示例,在DAO中你可以将返回的数据包装到LiveData中,如下代码所示:

重要:当你将数据通过应用架构的各个层从一个Room数据库传递到你的UI时,所有层中的数据多必须时LiveData:Room返回给Respository,然后Respository传递给ViewModel的所有数据必须是LiveData。你可以在观察viewModel中的数据的activity中创建一个观察者。

MutableLiveData

你可以独立于Room使用LiveData,但要这样做,你必须管理数据更新。然而,LiveData没有公共可用的方法来更新存储的数据。

这样,如果你想要更新存储的数据,你必须使用MutableLiveData来代替LiveData。MutableLiveData类增加两个公共的方法来允许你设置LiveData对象的值:setValue(T)和postValue(T)。

MutableLiveData通常用在ViewModel中,然后ViewModel只想观察者公开不可变的LiveData对象。

有关使用MutableLiveData的示例,请参阅架构组件的BasicSample代码。应用架构指南的示例也展示了MultableLiveData的使用。

观察LiveData

为了观察向用户展示的数据,在MainAcitvity中的onCreate()方法创建一个数据的观察者,并重载观察者的onChanged()方法。当LiveData改变,观察者会收到通知且onChanged()方法会执行。然后你更新缓存的数据,例如在适配器adapter,该adapter更新用户看到的页面。

通常你在ViewModel中观察数据,不是直接在Repository或者Room中。ViewModel会在后面的章节中进行描述。

下面的代码显示了如何附加观察者到LiveData中:

查阅LiveData文档学习使用LiveData的其他方式,或者观看架构组件:LiveData和LifeCycle视频。

Room数据库

Room是一个位于SQLite数据库之上的数据库层。Room负责处理你以前用SQLiteOpenHelper处理的日常任务。

使用Room:

  1. 创建一个继承RoomDatabase的公共抽象类。
  2. 使用注释来声明数据库的实体并设置版本号。
  3. 如果数据库不存在,请使用Room的数据库构建器创建数据库。
  4. 为数据库添加迁移策略。修改数据库模式时,需要更新版本号冰定义如何处理迁移。对于示例,销毁并重新创建数据库是一种很好的迁移策略。对于真正的应用程序,必须实现迁移策略。参见”使用Room理解迁移”。

提示:

  1. Room提供了SQLite语句的编译时检查。
  2. 默认情况下,为了避免糟糕的UI性能,Room不允许在主线程上发出数据查询。LiveData有需要时在后台线程通过自动的异步执行这个查询来运用这个规则。
  3. 通常对于整个APP你只需要一个Room数据库的实例。使你的RoomDatabase成为一个单例来阻止在相同时间打开数据库会有多个实例的情况,这会是非常糟糕的一件事。

这里有个完整的Room类的例子:

Repository

Repository是对多个数据源的访问进行抽象的类。Repository不是架构组件库的一部分,但它是代码分离和架构的最好实践。Repository处理数据操作,它为应用程序数据提供了干净api。

Repository管理查询线程并允许你使用多个后端。在一个常见的示例中,respository为决定是从网络拉取数据还是使用数据库中缓存数据来实现逻辑。

这里有个关于基本repository的完整代码:

提示:在这个示例中,repository没有做过多的事情。可以参阅运用在BasicSample示例中的实现。

APP架构指南包含了一个使用Web服务器来获取数据的更复杂的示例。

ViewModel

viewModel是一个类,它的角色是向UI提供数据并保存配置更改。viewModel充当了repository和Ui之间的通信中心。你同样可以使用viewModel在fragment之间共享数据。

viewModel是lifecycle库的一部分。有关这个主题的入门指南,请参阅ViewModel概览。

ViewModel以生命周期意识的方式来保存应用程序的UI数据,并在配置更改后继续保存。把你的UI数据从你的activity和fragment类分离可以让你更好的遵循单一职责原则:你的activity和fragment只负责绘制数据到屏幕上,然而你的viewModel负责持有和处理UI所需要的所有数据。

警告:从来不要传递上下文到viewModel实例中去。不要存储activity,fragment,view实例或者它们的上下文到viewModel中去。例如,一个activity可以被销毁并被创建多次在viewModel的生命周期中,例如当设备发生旋转时。如果你储存了activity的引用在viewModel中,你最终会得到指向该销毁activity的引用。这就是内存泄漏。如果你需要应用上下文,使用AndroidViewModel来代替viewModel。

在ViewModel中,对UI使用或展示的可变数据来使用LiveData,因此你可以添加观察者并来响应这个变化。

这里时一个完整的代码:

重要:viewModel不是一个为onSaveInstanceState()的替代品,因为viewModel在进程关闭时无法存活。请参阅保存UI状态。

为了学习更多,请观看“架构组件:viewModel视频”。

显示LiveData

最终,你可以显示所有这些有趣的数据给用户。

无论该数据什么时候变化,观察者的onChanged()方法会被调用。

在大部分基本实例中,这可以更新TextView的内容,如下代码所示:

另一个常见的实例是在与适配器一起工作的视图中展示数据。例如,如果你正在显示RecyclereView中的数据,onChange()方法更新缓存在适配器中的数据。

提示:获取数据存储库repository中的上下文引用的一种方法是扩展application类,并将context类型的成员添加到该自定义子类。

生命周期意识组件(Lifecycle-aware componeents)

在Android框架中国定义的大多数应用组件都附加了生命周期。生命周期是被你进程的操作系统或者框架代码所管理。它们是Android工作的核心,你的应哟个程序必须尊重它们。没有这样做,可能会触发内存泄漏甚至程序崩溃。Activity和fragment是生命周期感知组件的例子,而LiveData是生命周期感知组件。

一个常见的模式是在activity和fragment的生命周期方法中实现依赖组件的操作。例如,你可能需要一个在activity启动时,连接service的监听类,并在activity停止时,断开连接。在该activity中,你重载onStart()和onStop()方法来启动和停止该监听。

这代码看起来没什么问题,然而,一旦你有多个组件,使用这种模式会导致糟糕的代码组织和错误的扩散,比如可能的竞争条件。

生命周期感知组件执行动作以响应另一个组件生命周期状态的变化。例如,一个监听可以启动和停止它自己来响应一个activity的启动和停止。这使得代码组织的更好,通常更短,而且总是更容易维护。

Android.arch.lifecycle包提供了接口和类,让你构建生命周期感知组件,这些组件根据activity和fragment的生命周期状态自动的调整它们的行为。也就是说,你可以使任何类的生命周期敏感。

  1. 导入lifecycle包到你的Android工程中,请查阅添加组件到你的工程。
  2. 使用这些组件的更多信息,请参阅是哟个生命周期感知组件处理生命周期。

生命周期感知组件的用例

生命周期组件可以使你在不同的类中管理生命周期变得简单许多。例如,你可以使用生命周期感知组件:

  1. 在粗粒度和细粒度位置更新之间切换。

使用生命周期感知组件在位置app可见时开启细粒度位置更新,然后在app切换到后台时,选择到粗粒度位置更新。

  1. 停止和启动视频缓冲。

使用生命周期感知组件尽快启动视频缓冲,但推迟播放,直到应用程序完全启动。你同样可以使用生命周期感知组件来结束缓冲,在你app销毁时。

  1. 启动和停止网络连接。

当应应用程序在前台时,使用生命周期感知组件来启用实时更新网络数据,然后当应用程序移到后台时自动暂停。

  1. 暂停和恢复动画拖曳。

使用生命周期感知组件在应用程序切到后台时停止动画绘制,在程序返回前台时,恢复动画绘制。

Lifecycle基本示例

要使用基本生命周期观察,请将一个观察者添加到你想要观察的生命周期中,并指定你希望为感兴趣的生命周期事件发生什么。

下面时一个基本的生命周期观察者实现的代码示例。在真实项目中,你将会想要做更多有意义的事情,例如连接服务或轮询传感器。

分页库

分页库使应用程序更容易根据需要从数据源逐步加载信息,而不会重载设备或等待太长时间的大型数据库查询。

许多app可以处理大量数据,但每次只需加载和展示其中的一小部分数据。一个应用程序可能有数千项可以显示的商品,但它可能一次只需要访问其中的几十项。如果app没有经过精心设计,它可能会请求它不需要的数据,而这会给设备和网络带来性能负担。如果数据保存或者与远程数据库同步,这会减慢应用程序的运行速度,并浪费用户的数据计划。

分页库使用现有的解决方案解决问题。该库包含几个类,在你需要时可以简化请求数据处理过程。这些类还可以与现有的架构组件像Room无缝地工作。

在官方文档中学习更多的有关分页库的内容。

总结

假设你有展示数据的app,例如recyclerView中的列表,你可以添加数据到列表或者改变列表中的数据。如果app实现了上图中的架构,那么以下时正确的:

  1. 其中一些数据是基于Entity的实例,该实例表示存储库中的实体。
  2. 该Adapter缓存列表数据,当数据变化时,列表会自动更新和重新显示。
  3. 自动更新发生时因为在MainActivity中有个观察该数据的观察者,在数据发生变化时,观察者会收到通知。当数据发生改变时,观察者的onChanged()方法执行并更新adapter中的缓存数据。
  4. 数据可以被观察因为它是LiveData。观察到的是由ViewModel对象中的方法返回的LiveData<List<Entity>>。
  5. ViewModel从用户界面中隐藏了后端的一切动作。它为访问UI数据提供了方法且它返回LiveData所以MainActivity可以色织观察者关系。View,activity和fragment仅仅通过ViewModel来和数据进行交互。因此,它不关心数据来自于哪里。
  6. 在本例中,数据来自于repository。viewModel不需要知道respository和谁进行交互。它需要直到的是如何和repository进行交互,这是通过repository公开的方法实现的。
  7. Respository管理一个或多个数据源。对于这个架构,后端是一个Room数据库。Room是一个包装器,实现了一个SQLite数据库。Room做了很多你以前必须自己做的事情。例如,Room完成了你以前使用SQLiteOpenHepler类完成的所有事情。
  8. DAO将犯法调用映射到数据库查询,这样当repository调用诸如getAllEntities()这样的方法时,Room可以执行SELECT * from table ORDER BY entity ASC。
  9. 从查询返回的结果时可观察的LiveData。因此,每次在Room中的数据发生变化时,观察者接口的onChanged()方法被执行,UI被更新。

Android架构组件-Architecture Components相关推荐

  1. Android架构组件-App架构指南

    Android架构组件-App架构指南 Android架构组件-WorkManager Android架构组件- Room数据库的使用 Android架构组件-Lifecycle Android架构组 ...

  2. Android架构组件(二):LiveData

    前言 上篇文章我们分析了Lifecycle的使用和原理,相信我们已经学会了用Lifecycle将你所需的类添加声明周期管理,如果只是寥寥阅读也没关系,这里奉上(双膝跪地)上篇地址,Android架构组 ...

  3. 字节跳动Android金三银四解析:Android架构组件Room功能详解,深度好文

    前言 很多公司在招人这件事情上都会面临一个问题: "我们的招聘要求又不高,能做项目就行,但为什么就是招不到人?" 很多公司还面临一个问题,招聘的时候这人各方面都不错,但上岗了就是不 ...

  4. Android架构组件(三)——ViewModel

    Android架构组件(三)--ViewModel 上一篇文章讲到了Android架构组件之LiveData(Android架构组件(二)--LiveData),现在我们再来看看另一个成员ViewMo ...

  5. Android 架构组件 - 让天下没有难做的 App

    Google 为了帮助 Android 开发者更快更好地开发 App,推出了一系列组件,这些组件被打包成了一个整体,称作 Android Jetpack,它包含的组件如下图所示: 老的 support ...

  6. 初学 Android 架构组件之 Lifecycle

    在开发应用时,我们可能会基于一系列的生命周期实现某种功能.为了复用,也为了不让应用组件变得很臃肿,实现该功能时会选择与生命周期组件解藕,独立成一种组件.这样能够很方便地在应用组件中使用,比如:Acti ...

  7. 深圳腾讯内部Jetpack宝典意外流出!极致经典,堪称Android架构组件的天花板

    简介 Jetpack是一套库.工具和指南,可以帮助开发者更轻松地编写优质应用.这些组件可以帮助开发者遵循最佳做法.让开发者摆脱编写样板代码的工作并简化复杂任务,以便开发者将精力集中放在所需的代码上. ...

  8. Android架构组件LiveData+ViewModel

    前言 最近项目中有用到LiveData+ViewModel的架构组件,今天来学习一波.本篇文章参考:MVVM 架构,ViewModel和LiveData 所有语言为Kotlin. LiveData L ...

  9. 【大揭秘】Android架构组件ViewModel来龙去脉

    ViewModel是google官方的MVVM架构组件,目前已经集成到了最新的支持库中了,是MVVM架构的核心组件之一.不懂MVVM的请看之前的文章:(一)Android官方MVVM框架实现组件化之整 ...

最新文章

  1. 09Abstract Factory(抽象工厂)模式
  2. 深入浅出时序数据库之预处理篇——批处理和流处理,用户可定制,但目前流行influxdb没有做...
  3. Visual Studio 2010 模板缺失
  4. DNS原理及其解析过程(转)
  5. 用c++做贪吃蛇_用世界公认的变态羊毛做袜子!不用插电恒温37°C,还能抑菌99%...
  6. linux如何映射Windows下的磁盘为网络盘
  7. 大剑无锋之二分搜索、二分搜索时间复杂度、三分查找呢?
  8. 深度学习之基于CNN和VGG19实现灵笼人物识别
  9. Mac安装metasploit-framework【亲测有用】
  10. AI学习笔记(四)相机模型、图像聚类算法
  11. 递归,yield,参数槽
  12. 大型运输行业实战_day07_2_数据字典实现
  13. 【简单】Linux 搭建 UOJ
  14. 异常为当IDENTITY_INSERT设置为OFF时 解决办法
  15. matlab解耦合方程,如何在Matlab中求解耦合随机微分方程
  16. matlab图片背景分割,12.4.2 图像分割
  17. 用python编程一个走迷宫游戏_Python基于分水岭算法解决走迷宫游戏示例
  18. Word怎么在方框里打勾就是一个方框打上一个对号
  19. 3-24 浅谈多元正态分布的基本性质
  20. 一个游戏建模师一天的工作都在做什么?

热门文章

  1. 解决cd指令无法转换到其他盘的问题
  2. 【Qt炫酷动画】0.Qt动画类简介
  3. linux下qt判断网线是否插入
  4. JavaScript--秒表
  5. easyWechat微信jsapi支付
  6. Java成员变量默认赋值
  7. 连接Linux服务器黑屏,win下通过vnc连接linux服务器出现黑屏的问题
  8. 淇℃伅 Tomcat日志乱码的办法
  9. Java的特点与特性
  10. 两年 Android 经验面经(有赞等公司),安卓事件分发机制面试