Google官方架构Android Architecture学习(Kotlin+RxJava)

简述

AAC 是Google官方提供的项目架构,它使开发者快速构建一款 健壮、易测、强壮 的应用。

为什么使用它

我们总在寻找最佳的应用架构,从早期的MVC到后来的MVPMVVM。无疑我们使用它们的目的就是希望遵循一个架构原则 ,我们不希望将所有的代码都放入Activity或者Fragment中,任何与UI无关的代码都应该被剥离出去。我们希望的是各个组件各司其职,尽可能保证所有组件的职责单一性 。这样做无论是对我们程序的效率还是对于组件生命周期处理来说,都是非常友好并且高效的。

针对这一老生常谈的问题,Google 为我们隆重推出Android Architecture 官方认证架构,使用它,你将轻松解决 组件间交互、代码分层、生命周期管理、内存泄漏 等一系列随时可能让你崩溃的问题。

应用结构

在使用它之前,我们应当先了解构建一个 Android Architecture应用的结构,它看起来应该是这个样子:

UI --> ViewModel :Activity与Fragment作为UI层被置于整个架构最上方(最前端与用户交互),与之进行数据交流的仅有ViewModel层,也就是说Activity与Fragment中的一切UI变动都应当有ViewModel层进行控制,这也遵循了数据模型驱动UI 的架构原则。

ViewModel --> Repository:ViewModel层需要数据,那么就会有数据源,数据源也就是Repository层,你可以写很多的Repository类,在这个类中,它可以是通过 Retrofit 获取网络数据,亦或是通过Room获取本地SQL数据,哪种实现如何实现都不重要,只要 Repository 在ViewModel需求时返回给它需要的数据即可。

Repository --> Model :从Repository到model层,存在两种途径,Room获取本地数据库或者Retrofit(或其他网络请求方式)获取远程数据。Repository必须说明需要通过以上哪种方式去获取数据,接下来具体的获取数据的实现就交给 model层。

获取成功之后向上层返回数据(回调或者流式),最终UI层将数据表达出来。

引入依赖

project gradle 中

```

repositories {

google()

jcenter()

}

Module级 gradle 中

// ViewModel and LiveData

implementation"android.arch.lifecycle:extensions:1.1.0"

// alternatively, just ViewModel

implementation"android.arch.lifecycle:viewmodel:1.1.0"

// alternatively, just LiveData

implementation"android.arch.lifecycle:livedata:1.1.0"

annotationProcessor"android.arch.lifecycle:compiler:1.1.0"

// Room (use 1.1.0-alpha1 for latest alpha)

implementation"android.arch.persistence.room:runtime:1.0.0"

annotationProcessor"android.arch.persistence.room:compiler:1.0.0"

// Paging

implementation"android.arch.paging:runtime:1.0.0-alpha5"

// Test helpers for LiveData

testImplementation"android.arch.core:core-testing:1.1.0"

// Test helpers for Room

testImplementation"android.arch.persistence.room:testing:1.0.0"

```

你必须知道的组件

Lifecycle-Aware Components

LifecycleLifecycleOwner 组成。

Lifecycle:  一个用来保存组件生命周期的状态信息的类,它允许其他对象观察这些状态信息。主要使用了Event 和 State 这两个枚举类来跟踪绑定的组件的生命周期状态信息。

LifecycleOwner:  LifecycleOwner是一个接口,实现LifecycleOwner就表示这是个有生命周期的类,它有一个getLifecycle() 方法是必须实现的。Activity 和 Fragment(注:在AAC稳定的版本后) 都**已经实现了这个**接口,详细的实现可以自行查看代码。

ViewModel类

派生于ViewModel 的类,与特定的UI层 (Activity/Fragment类) 进行关联(数据交互),并且负责与数据的业务逻辑通信,比如调用其他的组件去加载数据。ViewModelView解耦,且不受配置改变的影响,例如由旋转屏幕导致的重新创建Activity。同时,在做多Fragment间通信时,如果每个Fragment都持有一个Activity的ViewModel,那么它们便可以不通过Activity直接通信,并且开发者无需关注 Fragment 的生命周期

LiveData

一个可以让数据具备可观察功能的类,持有可被观察的数据,它的写法是LiveData<T>。它使组件能够在不与 LiveData 存在明显依赖关系的前提下观察LiveData 中的数据的改变。LiveData 能感知带生命周期的组件的生命周期(但其本身不存在生命周期)并在相应状态作出相应处理,所以能有效防止对象内存泄漏。

Room

    持久化库,在应用中负责在网络获取数据前的本地数据获取,使应用在网络状况不佳时也不至于无法使用

一个栗子

我们已有数据类 User ,它有一个属性 id:String

首先是View层

仅仅是在 UserFragment 中拿到了一个 viewModel 引用以及 得到一个传进来的 uid

ViewModel层

UserViewModel 中拿到一个 LiveData<User> 的引用 ,kotlin 为我们写好了get() 方法,并且我们配合使用lazy使LiveData<User>  在第一次被使用时赋值

在 View 层观察变化并消费

Fragment 中我们对 viewModel 实例中的 user 进行了观察,在 observe时传入实现了 LifecycleOwner 的此 Fragment (也就是this),使 user 可以感受到Fragment的生命周期,其次传入了消费user的操作。至此,user 一旦发生变化,UI也就可以跟着变化了。

接下来就是实现数据的变更了

按理说是应该ViewModel 层获取数据并赋值给我们的LiveData ,那么必然在 ViewModel 中我们就需要拿到 ApiService 或着 Dao ,但我们并不希望 ViewModel 的关注点变得如此繁重,所以我们加入新的一层 Repository ,所有的数据请求逻辑处理将由 Repository 进行并将结果给予ViewModel 。这样做的好处不仅仅是使ViewModel 职责单一化,同时也意味着我们在想要使用其他方式获取数据时,上层并不需要关心,所有的变动都在 Repository 内进行就ok。

新增Repository

修改ViewModel

最后,在UI 层初始化一下

至此,

    我们使用AAC完成了一个从网络获取数据并更新UI的完整过程,当然这是没有进行任何封装的。然而AAC为我们提供的并不仅仅如此,我们还有一个重要的组件没有使用,那就是Room。

想象一个上百条数据的列表,我们可以使用上述方法在网络获取之后展示在 RecyclerView 中,这时我将应用kill掉,再次启动,应用又会再次请求网络数据,在数据返回之前我们的界面是空白的,即时我们在前一秒刚请求过一次列表数据。如果网络断开,那么更是导致我们的应用无法使用。这样的用户体验肯定是不佳的,所以我们使用Room,将网络数据存储在本地,在进行网络数据获取前先读区本地数据库。

接下来就开始使用Room

首先,用@Entity 注解去标注 User 类,表明它将作为数据库中的一张表,并未 id 添加主键注解

新建 MyDataBase 类派生于 RoomDatabase

                          注意:MyDataBase是抽象类,Room会为它自动提供一个实现

创建一个数据访问接口 Dao ,里面包含了我们对数据库的操作方法

可以发现这里查询数据的时候返回的是LiveData类型,因为Room知道数据库神恶魔时候被修改,当数据改变的时候它就会自动通知状态正为激活态的观察者们去更新数据或者UI。

在数据库类中引用Dao类

最后我们需要在 Repository 中加入 Room 的数据源

need-to-insert-img

    这个例子的数据获取方式是先获取本地数据,成功之后再发起网络请求,实际项目时可能还要判断各种条件,例如网络状况。但不管如何变化,获取方法都是如上所示。

我在代码中省略掉了apiServiceuserDao  的具体实现,因为这两个对象都应是单例,我的做法是将其实现写在 Application 中。当然,你可以配合依赖注入框架 Dagger2 ,kodein 对它们进行实现,这也是我现在正在学习的。

☝️到这里,这个栗子就结束啦~

☝️在实际项目中我们AAC进行封装使用,就可以非常愉快地和我们的硬件玩耍了~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350