Android架构初探
#一 背景
点评美团合并之后,业务需要整合,我们部门的几条业务需要往美团平台迁移,为了降低迁移成本,开发和维护成本,以及将来可能要做的单元测试,需要对架构进行相应的调整。之前的代码都堆在Activity或Fragment里面,UI,业务,数据混合在一起,就使得难以单独的复用和扩展、测试。
##
#二 目标
- 代码复用
- UI独立
- 业务独立
- 数据独立
- 可测试
##
#三 简洁架构
这里先引入简洁架构的概念,该架构由Uncle Bob提出,他认为一个架构应该具有以下特性
框架独立性
架构不应该依赖于现有的library,这样可以让你像工具一样去使用架构,而不是对你的系统添加约束
可测试
业务逻辑可以在不依赖UI,数据库,网络服务等其它外部因素的情况下进行测试
UI独立性
在不变动系统其它部分的情况下,可以很方便的改变UI,比如,在没有变动任何业务逻辑的情况下web ui可以被替换成console ui
数据库独立性
可以很自如的在Oracle,SQL Server之间切换,而不涉及业务逻辑
任何外部代理模块的独立性
业务逻辑应该不需要知道外部世界的任何事情
下图阐述了一个简洁架构的各个层之间的关系

- 内层不应该知道外层的任何情况
- 各层之间通过接口交互
- 上层依赖下层,但依赖于接口
应用中最重部分就是业务逻辑层。它负责解决应用所真正想解决的问题。该层不包含任何框架相关的代码,因此其代码应该可以在没有模拟器的情况下独立运行。这样,测试、开发和维护业务逻辑代码就要容易很多。而这就是干净架构的主要优势。
下面简单对以上几个概念进行简单的介绍
##Entities
数据部分,一个Entity可以是一个带有方法的对象,或者一个数据结构和方法的集合
##Use Cases
该层包含了应用特定的业务规则,封装了应用中所有的use cases。这些use cases从entities组装数据流,传递给业务使用。
该层的变更不应该影响到Entities,也不希望该层会被database,UI,或者其它通用框架的外部变化所影响到,该层应该独立于这些部分。
##Interface Adapters
该层是一些为了便于use cases和entities的数据转换的适配器。这一层包含GUI的MVC架构,展示层,Views和Controllers都属于该层。models更倾向于在controllers和use cases之间传递的数据结构,然后从use cases传递给Presenter和Views。
上面的这些原则足以构建高内聚,低耦合,可扩展的应用
##
#四 Android架构探索
一个应用基本可以划分为3个部分,UI,业务,和数据,而在移动端来说,更注重UI的展示,复杂的业务通常放在服务端。
针对这3部分,如何进行设计呢?
可以参考上面的基本原则 ,把整个项目拆分成3个不同的层级:
数据层— 业务层 — 展示层
每一层保持功能独立,上层依赖下层,但依赖于接口,而不是具体。每一层拥有自己的数据模型,做到依赖独立。

##
###4.1 表现层(Presentation Layer)
常见的模式有MVP,MVC,MVVM
表现层除了UI相关逻辑,不应该含有任何逻辑,这一层应该很轻,数据的获取和业务处理应该交给业务层和数据层,Presenter在该层由Use Cases组装,Use Cases会在新的线程执行一个任务并使用一个带有数据的回调用于渲染view,下图是MVP架构模块之间的基本关系

##
###4.2 业务层 (Business logic(Domain) Layer)
业务层可能有些模糊,哪些应该属于该层呢?
按照MVP的方式划分,很容易理解的是,所有的业务逻辑放到P中即可。但实际开发中,你会发现,稍微复杂的业务,P层的代码就会变得非常臃肿。我认为P的角色作为业务逻辑的组装更合适。业务逻辑可以进行相应的封装,比如
另外业务层应该是纯java代码,对android平台没有任何依赖,业务层向外暴露接口。

##
###4.3 数据层(Data Layer)
数据层提供了数据源,数据层也可以包括一些简单的数据处理,比如JSON的封装,一些model的转换,外部不关心具体如何获取数据的细节,只向数据层拿数据。比如下面展示了 仓库模式(Repository Pattern)来实现数据层,它的策略是采用工厂模式,传递不同的条件参数,获取不同的数据。

##
###4.4 测试 (Testing)
基于上面的架构,我们更容易进行测试,不同的分层之间完全独立,每一层也有自己相应的测试方案:
- Presentation Layer: 使用Android自带的
instrumentation和espresso做集成和功能测试。 - Domain Layer:
JUnit+mockito做单元测试。 - Data Layer:
Robolectric(这一层开始有Android相关的依赖)+junit+mockito做单元和集成测试
##
#五 表现层架构
MVC
Model–View–Controller (MVC) is a software architectural pattern for implementing user interfaces.*
MVP,MVC,MVVM 都是表现层的一种模式
这些架构相对于传统的开发方式,门槛高些,要想深入掌握和更高层次的理解各个层的职责,需要一定积累,对于一些简单的场景并不是一种好的方案,复杂的业务场景则会从中得到很多好处。
这些模式的好处
关注点分离,职责明确
o UI – 负责UI的渲染
o Presenter/controller – 负责响应UI事件并和Model交互
o Model – 负责业务行为和状态管理
代码重用性
关注点和责任分离之后,各层独立,可以增加代码的可用性
测试驱动
易于测试,只要写一个实现了ViewInterface的类即可测试,而不需依赖android平台
隐藏数据访问
使用这种模式之后,数据的访问代码就被划分到data层
扩展性高,可适配
将代码分离到Presenter,Controller和Model中,可以更自由的适配
##
##5.1 MVP
这里简单的介绍下MVP的基本元素
- M:数据实体,封装数据
- V:视图的渲染,事件的响应
- P:中间层,作为与M和V通讯的桥梁,组装业务逻辑
在MVP模式里通常包含4个要素
(1) View: 负责绘制UI元素、与用户进行交互(Activity或Fragment);
(2) View interface: View需要实现的接口,View通过View interface与Presenter进行交互
(3) Model: 业务Bean
(4) Presenter: 作为View与Model交互的纽带,承载了大部分的复杂逻辑
##
##5.2 MVP vs MVC
###相同点
- 分离了不同组件之间的责任,降低了View和Model之间的耦合
###不同点
- MVP中,View与model之间的耦合更低,不容许View直接访问Model,通过Presenter来交互,更加容易进行单元测试,因为View是通过接口来交互
- 通常View与Presenter的关系是一对一,复杂的View可能有多个Presenter
- MVC可以决定展示哪个View,Controller依赖于行为,而且可以被多个View共用
##
##5.3 MVP vs MVVM
MVP单项绑定,而MVVM采用双向绑定(data-binding),View的变动,自动反映在 ViewModel,Model的变动也会反映到View中


其实MVP中Model是很轻的,数据的获取和处理属于架构中的数据层和业务层,所以这一点并不是很让人能够理解。
本篇文章主要是对android架构的探索,目前我们采用的是data+domain+MVP这种架构模式。
后期会分享在架构调整中所遇到的问题和经验。
##
##项目
https://github.com/googlesamples/android-architecture
https://github.com/pedrovgs/EffectiveAndroidUI
https://github.com/dmilicic/Android-Clean-Boilerplate
https://github.com/android10/Android-CleanArchitecture
##参考文档
Architecting Android…The clean way?
https://segmentfault.com/a/1190000003966281?utm_source=APP&utm_medium=iOS&utm_campaign=socialShare
MVC or MVP Pattern – Whats the difference?
https://www.zhihu.com/question/30976423/answer/50181505
Android架构初探的更多相关文章
- React Native For Android 架构初探
版权声明:本文由王少鸣原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/171 来源:腾云阁 https://www.qclo ...
- Android开发学习之路--Android系统架构初探
环境搭建好了,最简单的app也运行过了,那么app到底是怎么运行在手机上的,手机又到底怎么能运行这些应用,一堆的电子元器件最后可以运行这么美妙的界面,在此还是需要好好研究研究.这里从芯片及硬件模块-& ...
- 一种更清晰的Android架构(转)
一种更清晰的Android架构 一种更清晰的Android架构 原文链接 : Architecting Android…The clean way? 译者 : Mr.Simple & So ...
- 《Android 性能测试初探》
移动测试站点推荐: https://testerhome.com/ 专项相关帖子推荐: <Android 性能测试初探>合集 移动无线应用专项测试浅谈 公开课: [腾讯课堂]Testerh ...
- Android Activity初探
原地址:Android Activity初探 Activity是一个应用中的组件,它为用户提供一个可视的界面,方便用户操作,比如说拔打电话.照相.发邮件或者是浏览地图等.每个activity会提供一个 ...
- Android架构分析之Android消息处理机制(二)
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本号:4.4.2 在上一篇文章中我们看了一个使用Handler处理Message消息的样例,本文我们 ...
- android学习——android架构
android架构:在了解全局的情况下进行细致化的分析才能更有效的学习android的运行原理,才能更深刻的理解android开发: 1.架构图直观 2.架构详解 2.1.Linux Kernel 2 ...
- 十九、Android Activity初探
原文:十九.Android Activity初探 Activity是一个应用中的组件,它为用户提供一个可视的界面,方便用户操作,比如说拔打电话.照相.发邮件或者是浏览地图等.每个activity会提供 ...
- Android架构分析之使用自定义硬件抽象层(HAL)模块
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本:2.3.7_r1 Linux内核版本:android-goldfish-2.6.29 在上一篇博 ...
随机推荐
- hdu5178 尺取
会爆int /* 给定数轴上一些点对,问有多少点对之间的距离差不超过k 点对排序后尺取法:枚举每个左边界,找到一个右边界使得 */ #include<bits/stdc++.h> #def ...
- Fiddler抓包4-工具介绍(request和response)
前言 本篇简单的介绍下fiddler界面的几块区域,以及各自区域到底是干什么用的,以便于各好的掌握这个工具 一.工具简介 1.第一块区域是设置菜单,这个前面2篇都有介绍 2.第二块区域是一些快捷菜单, ...
- 使用RabbitMQ实现延迟任务
场景一:物联网系统经常会遇到向终端下发命令,如果命令一段时间没有应答,就需要设置成超时. 场景二:订单下单之后30分钟后,如果用户没有付钱,则系统自动取消订单. 上述类似的需求是我们经常会遇见的问题. ...
- 小米note开启调试模式
1.刷机为开发版本. 2.拨电话界面输入 *#*#717717#*#* 开启调试模式. 3.驱动好像会自己安装.
- 设置Eclipse的类文件和xml文件代码自动补全
原文:https://blog.csdn.net/erlian1992/article/details/53706736 我们在平常编写代码的时候,不会记住大多数的类和文件的属性,方法等等,这就需要我 ...
- Docker 启动时容器无法联网
转自:https://blog.csdn.net/u014062332/article/details/52911405 启动docker web服务时 虚拟机端口转发 外部无法访问 centos 7 ...
- 高级Bash脚本编程指南《Advanced Bash-Scripting Guide》 in Chinese
<Advanced Bash-Scripting Guide> in Chinese <高级Bash脚本编程指南>Revision 10中文版 在线阅读链接:http://ww ...
- hdu 2036 求多边形面积 (凸、凹多边形)
<题目链接> Problem Description “ 改革春风吹满地,不会AC没关系;实在不行回老家,还有一亩三分地.谢谢!(乐队奏乐)” 话说部分学生心态极好,每天就知道游戏,这次考 ...
- 用js来实现那些数据结构02(数组篇02-数组方法)
上一篇文章简单的介绍了一下js的类型,以及数组的增删方法.这一篇文章,我们一起来看看数组还有哪些用法,以及在实际工作中我们可以用这些方法来做些什么.由于其中有部分内容并不常用,所以我尽量缩小篇幅.在这 ...
- Python学习——深浅拷贝
1.对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. >>> import copy # ######### 数字.字符串 ######### ...