过去的几个月中,在Tuenti上与同行例如@pedro_g_s和@flipper83进行了一些讨论。我决定去写一篇关于Android APP架构的文章。
 
写这个文章的目的是为了向你们展示一些我自己的方法,这些方法已经存在我的脑中好几个月了,主要来自于我自己的学习和研究。
 
开始行动
我们都知道编写高质量的软件是很难的而且很复杂:这不仅仅是满足需求,而应该是健壮的,易维护的,可测试的和可扩展的。所以提出的“简单的架构”理念是一种好的开发任何软件应用的方法。
 
想法很简单:“简洁架构”代表一组实践方式它的系统包含以下内容:
  • 独立的框架
  • 可测试的
  • 独立的UI
  • 独立的数据库
  • 独立的外部机构
并不是必须而且只能用4个圈表示(如图上所示),但是这里有一条从属规则必须知道。这个从属规则是:代码的依赖只能是指向内部的,而且只有内圈能知道外圈的内容。也就是外部的圈是无法知道内部圈的内容的。
 
以下是一些能让我们更好的熟悉和理解这个方法的一些名词解释:
  • Entities:应用的业务对象
  • Use Cases: 也叫交互器。用户实例由与Entities的数据流组成。
  • Interface Adapter:这里设置一些适配器将数据转换成user case 和entities能用的格式。Presenters 和 Controllers 属于这一层。
  • Framework 和Drivers: 这里是真正的实现区域,如:UI,工具,frameworks等等。
 
为了更好的解释,请参考这篇文章视频
 
我们的方案:
我会通过一个简单的例子来解释这个方案;创建一个简单的APP,这个APP实现的功能是:通过后台云来获取朋友或者用户的列表,当用户点击列表中的一项就会显示一个详细的页面。
 
Android架构
目的是为了独立业务单元,业务单元对于外围是未知的,然而这个业务单元能够进行独立测试。
 
我提议将工程分成3层来实现,每层都有自己的目的并与其它层独立。
 
因为每层都有自己的数据模型所以才能实现独立(你可以看到在代码中有一个数据映射表被用来进行完成数据的传送,这个是不想通过整个应用使用公用一套模型的代价)
 
以下是原理图:
注释:我没有使用外部的类库(除了使用gson去解析json数据和junit,mockito,robolectic和espresso 用来测试)。这样做的目的就是为了例子更简洁。另外不要讨厌去添加ORMs去存储硬盘数据或者其他相关的注入框架或者其他的工具或者你熟悉的库。(记住不要重复的制造车轮)
 
Presentation 层
 
呈现者在这层中由inteactors组成,他们在主UI线程之外的线程上工作,然后通过回调函数来传回数据并更新UI。
 
如果你想要一个更好的关于MVP和MVVM在Android UI的影响,可以看这篇文章
 
Domain 层
业务规则在这里,所有的逻辑关系也在这里。查看Android 工程,你会发现所有的Interactors的实现在这里。
这一层由无Android无关的纯Java代码构成。所有外部组件使用接口来对业务块进行联系。
 
Data层
应用中所有的数据都来自这一层,他们通过UserRepository(这个接口在domain层)的实现,使用Repository Pattern的一种策略,通过工厂模式,获取各种不同的数据源取决于中央条件。
 
在实例中,当我们通过Id来获取用户实例的时候,首先会选择磁盘缓存,如果不存在的话会通过网络获取数据然后保存在本地磁盘中。
 
这种机制的前提条件是数据源对于客户端来说是透明的,它不必关系数据是来自内存,磁盘或者是云数据库。只要相信可以获得到数据即可。
注释:在实例中,因为只是为了学习,我通过一个文件系统和android preferences来实现简单和原始的磁盘缓存。再次铭记不要重复造车轮。
 
Error Handling
这个是我们应该总是优先讨论,如果分享你的解决方案会更好。
 
我的策略是使用回调函数,如果一些错误发生在数据库,那么回调会有两个方法onResponse()和onError().第二个方法是会将异常封装在一个叫"ErorBundle"的类中:这个方法会带来一些困难因为存在一个链式的回调,一个接一个的知道错误到了presentation层,但是如果代码写的易读会将这种困难度减低。
另一方面,我会实现一个evetn bus 系统来处理错误事件,这个系统叫GOTO . 在我看来,有时如果订阅太多的事件,但是又没有控制紧密会导致一些事件丢失。
 
Testing
对于测试工作,我选了几种对应不同层的解决方案。
  • Prestation layer:使用android instrumtntation 和espresso去做集成和功能测试。
  • Domain layer:Junit 加mockito 对于单元测试。
  • Data Layer:Robolectric加junit加mockito用于集成和单元测试。
 
代码展示
代码在github上https://github.com/pedrovgs/EffectiveAndroidUI/,对于代码文件夹结构需要说明的是不同的层使用不同的模块。
  • presentation:这是android 模块,代表presetntaion Layer.
  • domain:纯粹的Java模块无任何Android关联。
  • data:获取数据的Android 模块。
  • data-test:针对Data layer的测试。由于使用Robolectric的限制,所以我要单独分离出来。
 
总结:
正如Uncle bob 所说“Architecture is about Intent,not Frameworks".我们在工作中总是会遇到各种挑战,但是如果使用这些技术,对于应用可以做到以下:
  • 易于维护
  • 方便测试
  • 高内聚
  • 低耦合
作为总结我强烈建议你去试试然后分享你的结果和经验。我们相信持续的改进一直是一种好的事情。
 
我希望你能通过本文获得有用的信息。

如何简单的构建Android?的更多相关文章

  1. gradle学习系列之eclipse中简单构建android项目

    看不到图片能够去訪问这个网址看看:http://pan.baidu.com/s/1o6FrFkA 一.什么是Gradle 官网www.gradle.org上介绍Gradle是升级版(evolved)的 ...

  2. 使用Maven构建Android项目

    http://www.ikoding.com/build-android-project-with-maven/ 之前一直在做WEB前端项目,前段时间接手第一个Android项目,拿到代码之后,先试着 ...

  3. 【Android】如何快速构建Android Demo

    [Android]如何快速构建Android Demo 简介 在 Android 学习的过程中,经常需要针对某些项目来写一些测试的例子,或者在做一些 demo 的时候,都需要先写 Activity 然 ...

  4. 用Gradle 构建android程序

    前言 android gradle 的插件终于把混淆代码的task集成进去了,加上最近,android studio 用的是gradle 来构建项目, 下定决心把android gralde 构建项目 ...

  5. 如何构建Android MVVM 应用框架

    概述 说到Android MVVM,相信大家都会想到Google 2015年推出的DataBinding框架.然而两者的概念是不一样的,不能混为一谈.MVVM是一种架构模式,而DataBinding是 ...

  6. gradle构建android项目详解

    1.用Gradle构建 1.1 工程结构 如图所示,这是一个不能更普通的Android的Gradle工程了. 根目录下面的settings.gradle当中主要是用来include子模块的,比如我们这 ...

  7. 使用组件构建Android应用程序

    原文链接:http://android.eoe.cn/topic/android_sdk 应用程序组件 Android's application framework lets you create ...

  8. 使用Gradle构建Android应用内测版本

    在开发应用的过程中,有时候需要比较当前线上版本和正在开发中的版本差异,目前的做法只能是在两个不同的设备上面安装线上版本和开发中的版本,因为当前版本在调试过程中会覆盖旧版本.本文通过使用gradle来构 ...

  9. 使用Gradle构建Android项目

    阅读目录 Gradle是什么? 环境需求 Gradle基本结构 任务task的执行 基本的构建定制 目录配置 签名配置 代码混淆设置 依赖配置 输出不同配置的应用 生成多个渠道包(以Umeng为例) ...

随机推荐

  1. 从spring框架中的事件驱动模型出发,优化实际应用开发代码

    一.事件起源 相信很多人在使用spring框架进行开发时,都会遇到这样的需求:在spring启动后,立即加载部分资源(例如:spring启动后立刻加载资源初始化到redis中).当我去解决这个问题时发 ...

  2. 通过XDocument方式把List写入Xml文件

    List<Person> list=new List<Person>{ new Person(){Name="张三",Age=50,Address=&quo ...

  3. mssql sqlserver 给已存在表添加新的字段及字段备注的方法

    转自:http://www.maomao365.com/?p=8102 摘要: 下文讲述向已存在表上添加新字段及字段备注的方法,如下所示: 实验环境:sql server 2008 R2 1. 添加新 ...

  4. 利用python开发app实战

    你说,我们的未来 被装进棺材,染不上尘埃 *** 我很早之前就想开发一款app玩玩,无奈对java不够熟悉,之前也没有开发app的经验,因此一直耽搁了.最近想到尝试用python开发一款app,goo ...

  5. JAVAFX之tableview界面实时刷新导致的内存溢出(自己挖的坑,爬着也要出来啊0.0)

    这几天遇到了一个问题,不幸开发的一个cs架构的工具,客户端开启后,内存一直在缓慢增长最终导致进程卡死,花了4天时间,终于爬出来了... 客户端通过timer定时器每30秒查询一次数据库以及一些业务逻辑 ...

  6. linux 上安装多个不同版本的mysql 踩的坑

    最近由于业务需要,考虑使用json类型,据了解 mysql 在版本5.7中可以支持 json 类型的数据支持,但同时目前开发环境中使用的是 mysql 5.6版本,上面还有很多项目的数据库在上面,同时 ...

  7. git客户端保存用户名密码

    [转载]原文地址:https://blog.csdn.net/qq_26819733/article/details/52735123/ 看图说话,直接在Tortoisegit的设置中,点git-&g ...

  8. 构造方法、This关键字、静态与封装的特性与作用

    1.构造方法 构造方法是一种特殊的方法,专门用于构造/实例化对象. 构造方法根据是否有参数分为无参构造方法和有参构造方法. 1.1无参构造方法 无参构造方法就是构造方法没有任何参数.无参构造方法在创建 ...

  9. Python:SQLMap源码精读—基于时间的盲注(time-based blind)

    建议阅读 Time-Based Blind SQL Injection Attacks 基于时间的盲注(time-based blind) 测试应用是否存在SQL注入漏洞时,经常发现某一潜在的漏洞难以 ...

  10. 【重学计算机】机组D5章:指令系统

    1. 指令系统基本概念 指令集:一台机器所有指令的集合.系列机(同一公司不同时期生产):兼容机(不同公司生产) 指令字长:指令中包含的二进制位数,有等长指令.变长指令. 指令分类 根据层次结构:高级. ...