MVVM_Android-CleanArchitecture
前言
"Architecture is About Intent, not Frameworks" - Robert C. Martin (Uncle Bob)
Uncle Bob 的这句话套在 MVVM 上也是适用的, MVVM 也仅仅是架构模式
(Architectural pattern),其有一套自己的理论概念(pattern)而不是规定的具体实现(或 Frameworks)。早之前在知乎上相关问题的回答(android UI设计MVVM设计模式讨论?)中也简单提到过 MVVM 了,M-V-X 的关系如上图,那么这一次博主把 Fernando Cejas(android10) 的Android-CleanArchitecture 项目中的 MVP 实现重构成了用 MVVM 来实现。所以看这篇文章最好是先搞清了 Fernando Cejas(android10) 的 Android-CleanArchitecture sample app 和对应的两篇文章(见参考)。整个历程也算比较愉快,没什么不良反应,这篇文章理所当然会重点说说 MVVM 的实现、 Data Binding 等相关的东西。那为什么拥抱 MVVM 呢。当然是 Google 推出官方的 data binding 啦,下一次的 Android MVVM 热潮应该就是 data binding 放出正式版了。
分层架构与 M-V-X
首先还是先来说说 分层架构
与 MVC
or M-V-X
之间的关系。分层架构是一种常见的软件应用架构,在 Java 程序中可以算是一种应用标准了,通常又叫 N 层架构,而最常见的是 3 层架构,它包含如下 3 层:
展示层(Presentation tier),也称为 UI 层,也就是程序的界面部分。
业务层(business logic(domain) tier), 业务层,是最为核心的一层。
持久层(Data tier),数据持久层。
3 层架构是存在物理上分层概念的,从上往下即展示层、业务层、持久层,也从上往下由上一层依赖下一层。不同层之间也是 高内聚低耦合
的体现,层内高内聚,层间低耦合,层
是层内具体工作的高度抽象。低耦合则是依赖倒转原则体现出来,高层依赖于下层的抽象而不是具体。
接下来先说 M-V-X 的鼻祖 MVC,Model–View–Controller (MVC) is a software architectural pattern for implementing user interfaces.,所以 MVC 模式是为用户界面设计的,在 3 层架构中,MVC 是属于展现层的部分,所以 MVVM 作为 MVC 的演进在与分层架构的关系上也是一样。经常会看到 3 层架构与 M-V-X 混为一谈的内容,这是不正确的,虽然都是 3 部分的内容但是不能 简单地 把两者的每一部分对应起来,我们应该理解为,在分层架构中 M-V-X 是在展示层(Presentation tier)的应用。这些软件工程理论的东西就这样了,都是大师们留下来的东西,不要随便套上自己的概念。
Android-CleanArchitecture
Fernando Cejas(android10) 的 Android-CleanArchitecture 项目中也是采用典型的 3 层架构,其中 Presentation 展现层采用了 MVP 模式,如果还未了解过 MVP,可以看看我之前写的文章:Android中的MVP。不过 Google 推出官方的 data binding
之后我觉得基本可以不用采用 MVP 了,在 M-V-X 中, MVP 与 MVVM 算是比较接近的了但 MVP 中的一堆 View 接口也是让人头疼的,而拥有 data binding 的 MVVM 则解决了这个问题,所以请大胆拥抱 MVVM。So,下面几点是当中除 MVVM 外涉及到的东西,MVVM 放到下一节再讲。
Dagger
自带 Dagger
信仰光环者障眼之术开启, 哈哈,你们看不到接下来的这句话了。。我现在也是持不赞成 di 的观点的人(在 Android 中、、、),可以看看这场撕逼:依赖注入是否值得?。结果就是我把原项目的依赖注入模块去掉了,对于测试中的类中的成员变量来说本来就是 Mock 抽象接口,那就直接对接口或抽象类直接 Mock 操作就可,毕竟依赖注入的解耦依然是取决于需要注入的对象的抽象,维护依赖注入模块(Module)也是负担,测试代码中又要多写一套注入控制的 Dagger Module 代码。。
RxJava、RxAndroid
先说 AsyncTask,对其已经不再想吐槽,这么重要的异步实现,版本间(Android Api)代码改来改去,又顺序又无序、又单线程执行又并发执行、内存泄露、、、。所以对于采用 RxJava 即使不采用函数响应式编程的大概念,用它来替换 AsyncTask 和 Thread + Handler 也是推荐的。此外使用 Rx 后也不需要事件总线的框架了,对于回调监听直接在数据操作的 Observable 上注册观察者即可,相对于事件总线来说是更精准的(单线)的监听。而事件总线的话则是更加松耦合的,出错的话会更加难排查,这里就不再展开了。
Lambda
个人、团队喜好,代码简洁了很多但是代码的逻辑比较不好直观理解了,原项目也只有 3 处代码用到,故而去掉了。
此外,对于领域驱动设计(DDD)中 Repository,原项目中把其实现放到了 data 层去实现(接口),造成 data 层会依赖其上一层(domain 业务层),作为分层架构个人认为不合适所以重新把它调整了。根据 DDD,个人认为 Repository 它的存在让领域层(domain 业务)感觉不到数据访问层的存在,它提供一个类似集合的接口提供给领域层进行领域对象的访问。Repository 是仓库管理员,领域层需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。
MVVM
理论简述
按照常理,先来说基本概念:
Model,domain model(领域模型)或是数据层代表的数据模型,也可以理解为用户界面需要显示数据的抽象(数据)
View, 应用的界面
ViewModel,binder 所在之处,是 View 的抽象,对外暴露出公共属性和命令,是 View 与 Model 的(绑定)连接器
此外还有必不可少的一部分:Binder,Android 中也就是 Data binding 了,提供 View 与 Model 的绑定功能。下面是结构图:
Android 中实现
目前 Android 的 data binding 还是 beta,还只是 one-way
单向绑定,功能上还有所欠缺、控制性也还不强,但是把它写出来还是没问题的。对于 Activity、Fragment 而言仅仅是作为 Java View 看待,与 XML 对应,所以里面只有 View 的展现逻辑,此外没有其它代码。一个 Activity 或 Fragment(一般都 with XML) 对应一个 ViewModel,对于一个基础 View(XML)可以通过继承对应的 ViewModel 实现重用,本文的代码也有体现。对于 Activity 和 Fragment 的View 状态保存恢复也通过 ViewModel 处理。因为 binding 的入口在 Activity 或 Fragment 中,所以为了方便写个基类处理 ViewModel 和 Binding 的初始化,然后在 对应的 XML 里加上 ViewModel 的 variable, XML 里不再有其它数据对象的 variable。
public abstract class BaseActivity<VM extends ViewModel, B extends ViewDataBinding> extends Activity {
private VM viewModel;
private B binding;
public void setViewModel(@NonNull VM viewModel) {
this.viewModel = viewModel;
}
public VM getViewModel() {
if (viewModel == null) {
throw new NullPointerException("You should setViewModel first!");
}
return viewModel;
}
public void setBinding(@NonNull B binding) {
this.binding = binding;
}
public B getBinding() {
if (binding == null) {
throw new NullPointerException("You should setBinding first!");
}
return binding;
}
}
ViewModel 中通过 ObservableField 来达到细粒度的控制,绑定操作都放在 ViewModel 里,然后 ViewModel 里可以有多个 domain 中的 Interator(UseCase) 来得到 View 需要渲染的数据 Model。对于 ObservableField 的绑定操作和命令操作(Command)都是暴露的,也易于测试。binding 现在缺少手动在 Java 代码中注册通知事件的功能,比如有些 model 的渲染必须通过 Java 代码来操作的话就需要了,在 Activity(Java View) 中通过向 Binding 注册通知回调,而目前只能在 XML 中知道,当然目前也可以自己实现,方法也有多种:接口回调、EventBus、RxBus。。
架构图
除了 Persenter 改成 ViewModel 的逻辑、Repository 的抽象和具体都在 domain 外,其他部分基本一致,采用的测试也一致。
Clean Architecture:
MVVM_Clean-Architecture tier:
MVVM_Clean-Architecture put all:
Refactor
Talk is cheap. Show you the code. ↓↓↓
MVVM_Android-CleanArchitecture
需要注意的是 include 标签的 XML 节点中要使用到根节点中 data 标签里设置的 viewModel variable 的话需要这样设置;
<include
layout="@layout/view_retry"
bind:viewModel="@{viewModel}"/>
抽象类 ViewModel 中设置了 @Command 和 @BindView 注解,只起到清晰提醒作用。
具体重构更改可以查看 commit 记录:MVVM_Android-CleanArchitecture commits。可以看到 Activity 和 Fragment 的代码是很清爽的,比 MVP 更清爽,因为 View 的数据渲染操作交给 binder 去处理了。对 Activity 或其对应界面进行 UI 测试的话,Mock 出 model 代表的数据然后传递给 ViewModel 中 @BindView 暴露出的方法,然后检验视图对数据的正确显示就行了,也就是 View 对 Model 做了正确的渲染。
参考
企业应用架构模式
Architecting Android…The clean way? (Android-CleanArchitecture 的文章,译文略)
Architecting Android…The evolution (Android-CleanArchitecture 的文章,译文略)
Approaching Android with MVVM
ANDROID DATABINDING: GOODBYE PRESENTER, HELLO VIEWMODEL!
END
本文源码:MVVM_Android-CleanArchitecture or Rocko-Android-Demo(-MVVM_Android-CleanArchitecture)
MVVM_Android-CleanArchitecture的更多相关文章
- 分享我的CleanArchitecture for Razor Page项目模板
这个项目是参考和整合了jasontaylordev/CleanArchitecture 和 blazorhero/CleanArchitecture 代码基础上,重构出来的新的项目,这两个项目都是非常 ...
- 一个遵循CleanArchitecture原则的Asp.net core轻量级开源项目
这是一个基于最新的ASP.net core 5.0创建Razor Page应用程序解决方案模板.遵循Clean Architecture的原则,以最求简洁的代码风格和实现快速开发小型的web业务系统的 ...
- CleanArchitecture Application代码生成插件-让程序员告别CURD Ctrl+C Ctrl+V
这是一个根据Domain项目中定义的实体对象(Entity)生成符合Clean Architecture原则的Application项目所需要的功能代码,包括常用的Commands,Queries,V ...
- 【转】GitHub 排名前 100 的安卓、iOS项目简介
GitHub Android Libraries Top 100 简介 排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果, 然后过滤了跟 Android 不 ...
- GitHub Android Libraries Top 100 简介
本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果, 然后过 ...
- APP架子迁移指南(二)
接上一篇,这一篇开始用android来解释MVP概念.八股式的架子结构和命名规范.我在准备这篇文章的时候还看到不少在MVP基础上衍生的架子思路,底子是MVP没错,但命名有区别.复杂度变了.架子也用到了 ...
- 2016年GitHub 排名前 100 的安卓、iOS项目简介(收藏)
排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果, 然后过滤了跟 Android 不相关的项目, 所以排名并不具备任何官方效力, 仅供参考学习, 方便初学者 ...
- 64.GitHub 排名前100的android项目简介
GitHub Android Libraries Top 100 简介 排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果, 然后过滤了跟 Android 不 ...
- 100个Github上Android开源库
项目名称 项目简介 1. react-native 这个是 Facebook 在 React.js Conf 2015 大会上推出的基于 JavaScript 的开源框架 React Native, ...
- GitHub上排名前100的Android开源库介绍(来自github)
本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍,至于排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果,然后过滤了 ...
随机推荐
- MVC知识总结(前序)
距离2015年的来临还有1天的时间,是时候总结一下今年的经过脑子的知识了,由于今年里工作中接触MVC的时间特别多,所以打算针对MVC这个东西的知识进行一个总结,好歹对得起在几个项目中用了MVC来进行开 ...
- Sql遍历更新脚本
DECLARE My_Cursor CURSOR --定义游标 declare@indexId int FOR (SELECT * FROM dbo.GalleryPhoto) --查出需要的集合放到 ...
- 转载-优秀程序员的十个tips
理解技术债务 技术债务就像信用卡一样,会有很高的利息,时间越长,修复所化的代价就越大.团队应该培养一种保证设计质量的文化,鼓励重构.同时应当鼓励其它有关代码质量的实践. 保持对原理的好奇心 做Andr ...
- SQLServer 在Visual Studio的连接方法
一.Sql Server 在Visual Studio的连接有两种方法: (1)本地计算机连接; [c#] view plaincopy string s = "Data Sourc ...
- ITextSharp用来生成 PDF 的一个组件
iTextSharp 是用来生成 PDF 的一个组件,在 1998 年夏天的时候,Bruno Lowagie ,iText 的创作者,参与了学校的一个项目,当时使用 HTML 来生成报告,但是,使用 ...
- bzoj1260[CQOI2007]涂色paint
思路:区间dp,用f[i][j]表示区间[i,j]的答案,然后转移即可. #include<iostream> #include<cstdio> #include<cst ...
- (转)iOS中3种正则表达式的使用与比较
.利用NSPredicate(谓词)匹配 例如匹配有效邮箱: NSString *email = @“nijino_saki@.com”: NSString *regex = @"[A-Z0 ...
- 修复Windows7的便签问题
工作的时候,喜欢利用Windows的附件“便签”,将自己要做的事情一一列在上面,显示在桌面上, 今天突然发现便签损坏,系统是元数据损坏,后来在网上查到解决方法,特此记录: 1. 以管理员身份运行 cm ...
- zlib1.2.8 编译小记
官网下载:http://www.zlib.net/ 用vs命令行工具运行zlib-1.2.8\contrib\masmx86\bld_ml32.bat 用vs2012打开zlib-1.2.8\cont ...
- jquery放大镜插件与样式
这是放大镜插件链接,我已经上传到我博客http://files.cnblogs.com/valiant1882331/%E6%94%BE%E5%A4%A7%E9%95%9C%E6%8F%92%E4%B ...