AAC架构一:AAC架构简介


Jetpack是2018年谷歌I/O 发布了一系列辅助android开发者的实用工具库,以帮助开发者构建出色的 Android 应用。

Jetpack 通过提供现代化应用架构以及提供强健的向后兼容能力等方式,让开发者能够快速、轻松地创造拥有卓越性能的高质量应。

Jetpack是Google重点打造的下一代 Android 组件,可以说它就是Android的未来方向,所以掌握好Jetpack,你就掌握好了未来战场的强大武器。

本猿准备通过一系列的文章去记录我对JetPack的学习要点及心得。那么我们就从AAC开始吧。
AAC架构一:AAC架构简介
AAC架构二:AAC架构应用举例


一、前言

基于目前的项目的架构比较陈旧,而且AAC架构也推广了有一段时间,基本上处于比较成熟的状况了,于是决心下来,把架构进行更新。

很久之前就想开始写点关于Jetpack这个包集相关的文章,但是,出于种种原因,一直搁置着,借着这次更新架构,顺便把这个心愿了了。

AAC架构是Jetpack里比较核心的一部分,我们就从这个点出发,逐步体验一下Jetpack的强大。

二、常用的架构原则

我们先回顾一下,大家日常开放中经常用到的架构原则。

1、分离关注点

要遵循的最重要的原则是分离关注点,一种常见的错误是在一个 Activity Fragment 中编写所有代码。这些基于界面的类应仅包含处理界面和操作系统交互的逻辑。您应尽可能使这些类保持精简,这样可以避免许多与生命周期相关的问题。

请注意,您并非拥有 ActivityFragment 的实现;它们只是表示 Android 操作系统与应用之间关系的粘合类。操作系统可能会根据用户互动或因内存不足等系统条件随时销毁它们。为了提供令人满意的用户体验和更易于管理的应用维护体验,您最好尽量减少对它们的依赖。

2、通过模型驱动界面

另一个重要原则是您应该通过模型驱动界面(最好是持久性模型)。模型是负责处理应用数据的组件。它们独立于应用中的 View 对象和应用组件,因此不受应用的生命周期以及相关的关注点的影响。

持久性是理想之选,原因如下:

  • 如果 Android 操作系统销毁应用以释放资源,用户不会丢失数据。
  • 当网络连接不稳定或不可用时,应用会继续工作。

应用所基于的模型类应明确定义数据管理职责,这样将使应用更可测试且更一致。

基于常见的架构原则,如果你的架构非常陈旧或者比较凌乱,我觉得还是非常有必要更新换代的,这里,我推荐使用ACC架构。

三、AAC架构

我们先来看一下定义:

Android Architecture Components,简称 AAC,一个处理UI的生命周期与数据的持久化的架构,它基于管理UI组件生命周期和处理数据持久性的类,可以帮助您设计健壮、可测试和可维护的应用程序。

1、AAC 的核心

AAC架构的核心部分包括:

Lifecycle, LiveData, ViewModel 以及 Room

  • Lifecycle帮助您管理 Activity Fragment 生命周期。生存配置更改,避免内存泄漏并轻松将数据加载到UI中。
  • 使用LiveData 构建数据对象,以便在基础数据库更改时通知视图。
  • ViewModel存储在应用程序轮换时未销毁的UI相关数据。
  • Room是一个SQLite对象映射库。使用它来避免样板代码并轻松地将SQLite表数据转换为Java对象。Room提供SQLite语句的编译时检查,可以返回RxJava,Flowable和LiveData observable。
优势
  • 通过它可以非常优雅的让数据与界面交互
  • 并做一些持久化的东西
  • 高度解耦
  • 自动管理生命周期
  • 而且不用担心内存泄漏的问题.
架构图如下:
image

请注意,每个组件仅依赖于其下一级的组件。例如,Activity 和 Fragment 仅依赖于视图模型。存储区是唯一依赖于其他多个类的类;图中,存储区依赖于持久性数据模型和远程后端数据源。

这种设计打造了一致且愉快的用户体验。无论用户上次使用应用是在几分钟前还是几天之前,现在回到应用时都会立即看到应用在本地保留的用户信息。如果此数据已过时,则应用的存储区模块将开始在后台更新数据。

注意:任何应用编写方式都不可能是每种情况的最佳选择。话虽如此,但推荐的这个架构是个不错的起点,适合大多数情况和工作流。如果您已经有编写 Android 应用的好方法(遵循以上提到的常见的架构原则),则无需更改。

2、LifeCycle & LifecycleOwner

  • Lifecycle:它是一个持有 Activity/Fragment 生命周期状态信息的类,并且允许其他对象观察此状态。

  • LifecycleOwner:是一个具有单一方法的接口。如果一个类实现了此接口,则该类中需要持有一个 Lifecycle 对象,并通过LifecycleOwner.getLifecycle() 方法返回该对象。

    并不是只有 Activity 和 Fragment 才可以实现 LifecycleOwner 接口的,任何和 Activity/Fragment 生命周期有关系的类都可以实现此接口。通过实现此接口,该类完全是生命周期可感知的,只需要对它进行初始化,它就可以进行自己的初始化和清理操作,而不受其 Activity/Fragment 的管理

activity活动图:


activity活动图

获取当前activity的状态:

        if(getLifecycle().getCurrentState() == Lifecycle.State.RESUMED){
            //todo ...
        }

3、LiveData

LiveData 是一个数据持有类,它持有一个值并且该值可以被观察。不同于普通的可观察者,LiveData 遵从应用组件的生命周期,这样 Observer 便可以指定一个其应该遵循的 Lifecycle。

如果 Observer 所依附的 Lifecycle 处于 STARTED 或者 RESUMED 状态,则 LiveData 认为 Observer 处于活跃状态。

可以感知组件生命周期的 LiveData 给我们提供了一种可能:可以在多个 Activity、Fragment 之间共享它。

使用 LiveData 会有以下几个优势:

  • 避免内存泄露:因为 Observer 是绑定到 Lifecycle 对象上的,当 Lifecycle 对象被销毁的时候,LiveData 对象也会被自动清除
  • 不会因为 Activity 停止而使应用崩溃:如果 Observer 所绑定的 Lifecycle 处于闲置状态(例如:Activity 处于后台运行时),他们不会接收到改变的事件
  • 始终保持最新的数据:如果一个 Lifecycle 重新启动以后(例如:Activity 从后台重新开始运行于前台),它会接收到最新的数据(除非没有最新的数据)
  • 正确处理配置改变:如果一个 Activity 或者 Fragment 以为配置改变(例如:旋转屏幕)被重建以后,LiveData 将会接收到最新的数据
  • 资源共享:通过单例模式,可以在多个 Activity 或者 Fragment 之间共享 LiveData 数据。
  • 不再手动的处理生命周期:Fragment 只有在处于活跃的时候才会观察 LiveData 数据。由于 Fragment 提供了 Lifecycle 对象,所以 LiveData 会管理这一切。

有时候,也许想在 LiveData 被下发到 Observer 之前,改变 LiveData 的值,或者是基于当前的 LiveData 下发另一个不同的 LiveData 值。Lifecycle 包中的 Transformations 可以实现这样的功能。

Transformations.map(),使用此方法,可以将 LiveData 传递到下游

LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});

Transformations.switchMap(),和 map() 方法类似,使用 switchMap() 应用于 LiveData 的值并解包,然后将结果传递到下游。传递给 switchMap() 的方法必须返回一个 Lifecycle

private LiveData<User> getUser(String id) {
  ...;
}
LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );

使用这两个转换,允许在整个调用链中携带观察者的 Lifecycle 信息,这样的话,只有在观察者观察到 LiveData 的返回值时,才会运算这些转换。

当你需要在 ViewModel 中添加一个 Lifecycle 对象时,Transformations 或许是一个好的解决办法。

android.arch.lifecycle.Observer

用于对LiveData增加监听,使用的方法为LiveData.observe(LifecycleOwner, Observer), 对于一些不需要的observer建议及时移除掉,LiveData.removeObserver(Observer),因为如果没有移除掉,当数据刷新的时候还是会一直调用

基于LiveData的特性,你会发现,它完全具备事件总线的要求,而且还能感知生命周期,而且还是Google官方API,这地多带劲呀。后面准备写一个用LiveData做事件总线的文章,替代第三方的事件总线

4、ViewModel

ViewModel 类是用来存储和管理 UI 相关的数据,这样在配置发生变化(例如:屏幕旋转)时,数据就不会丢失。
由于应用程序组件(例如:Activity、Fragment),具有一个由 Android Framework 管理的生命周期,Activity 或 Fragment 在某些情况下(比如:内存紧张或者屏幕旋转)会发生销毁或者重新创建的情况。这样就会带来一些问题:

  • 由于 Activity 或者 Fragment 有可能会被销毁或重新创建,所以保存于其中的数据有可能会丢失
  • 在 Activity 或者 Fragment 中会经常发起一些需要一定时间才会返回结果的异步请求调用
  • 如果把处理应用数据、完成响应用户操作、处理系统通信工作的代码都写在 Activity 或者 Fragment 中,那么 Activity 或者 Fragment 将会变得非常的臃肿,给维护工作带来一定的困难

针对以上问题,Lifecycle 提供了一个叫 ViewModel 的类,一个 UI 控制器的帮助类,用来为 UI 准备数据。

在配置更改的时候,ViewModel 会被保留,以便其保存的数据可以立即传递给重新创建的 Activity 或者 Fragment 实例中。如果 Activity 被重新创建,它将会收到由之前的 Activity 或者 Fragment 创建的 ViewModel 实例。当所有者 Activity 被销毁以后,Framework 会调用 ViewModel.onCleared() 清楚系统资源

注意:由于ViewModel超出了具体的Activity和Fragment实例生命周期,所以它不应该引用View或任何可能持有对活动上下文的引用的类。 如果ViewModel需要应用程序上下文(例如,找到系统服务),则可以扩展AndroidViewModel类,并在构造函数中接收应用程序的构造函数(因为Application类扩展了Context)

viewModel生命周期图:

image

ViewModel vs SavedInstanceState

  • ViewModels 提供了一种在配置更改时保存数据的简便方式,但是如果应用进程被操作系统杀死,那么数据则没有机会被恢复。
  • 通过 SavedInstanceState 保存的数据,存在于操作系统进程的内存中。当用户离开应用数个小时之后,应用的进程很有可能被操作系统杀死,通过 SavedInstanceState 保存的数据,则可以在 Activity 或者 Fragment 重新创建的时候,在其中的 onCreate() 方法中通过 Bundle 恢复数据

因为ViewModel的生命周期是和Activity或Fragment分开的,所以在ViewModel中绝对不能引用任何View对象或者任何引用了Activity的Context的对象。如果ViewModel中需要Application的Context的话,可以继承AndroidViewModel。

四、结语

到这里,相信你已经对AAC架构有一些初步的了解,AAC是JetPack中的一部分,JetPack架构还包含了很多其他比较实用的组件:

DataBinding:以声明方式将可观察数据绑定到界面元素;
Navigation:处理应用内导航所需的一切,这个组件对于fragment的管理特别有用;
Paging:逐步从您的数据源按需加载信息;
WorkManager:管理您的 Android 后台作业;
………………

Google这两年一直在对这一套的架构进行不断的更新,就是想要解决Android开发中的很多痛点,以后Architecture Components作为Android开发的基础架构也是必然的趋势。

基于这一点,我们准备通过一系列的文章去记录我对JetPack学习的要点。那么我们就从AAC开始吧。

推荐阅读更多精彩内容