英文原文:

http://fernandocejas.com/2015/07/18/architecting-android-the-evolution/
http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/


中文翻译:

http://android.jobbole.com/81153/
https://zhuanlan.zhihu.com/p/20001838

对应代码:

https://github.com/android10/Android-CleanArchitecture
https://github.com/zhengxiaopeng/MVVM_Android-CleanArchitecture
https://github.com/zhengxiaopeng/Rocko-Android-Demos/tree/master/architecture/MVVM_Android-CleanArchitecture

对于好的文章真的会有一种忍不住要收藏的感觉,现在就无耻得转载这篇文章分享给大家:

开始

我们知道编写高质量软件是既困难又复杂的:不仅是满足需求方面,还要健壮、可维护、可测试,并且足够灵活以适应增长和变化。这就是“代码整洁之道”的来源,并可以成为开发任何软件应用程序的良好方法。
思想很简单:代码整洁之道代表构建系统的一组实践:

  • 独立于框架。
  • 可测试性。
  • 独立于UI。
  • 独立于数据库。
  • 独立于任何外部代理。

我们并不要求一定要用四环结构(如图所示),这只是一个示例图解,但是要考虑的是依赖项规则:源码依赖项只能向内指向,内环里的所有项不能了解外环所发生的东西。

以下是更好地理解和熟悉本方法的一些相关词汇:

  • Entities:是指一款应用的业务对象
  • Use cases:是指结合数据流和实体中的用例,也称为Interactor
  • Interface Adapters: 这一组适配器,是负责以最合理的格式转换用例(use cases)和实体(entities)之间的数据,表现层(Presenters )和控制层(Controllers ),就属于这一块的。
  • Frameworks and Drivers: 这里是所有具体的实现了:比如:UI,工具类,基础框架,等等。

想要更具体,更生动丰富的解释,可以参考这篇文章或者这个视频。

场景

我会设置一个简单的场景来开始:创建一个简单的小app,app中显示从云端获取的一个朋友或用户列表。当点击其中任何一个时,会打开一个新的窗口,显示该用户的详细信息。
这里我放了一段视频,大家看看这个视频 (需翻墙)大概就可以对我所描述的东西了解个大概了。

Android应用架构

这一对象遵循关注分离原则,也就是通过业务规则让内环操作对外环事物一无所知,这样一来,在测试时它们就不会依赖任何的外部元素了。
要达到这个目的,我的建议就是把一个项目分成三个层次,每个层次拥有自己的目的并且各自独立于堆放运作。
值得一提的是,每一层次使用其自有的数据模型以达到独立性的目的(大家可以看到,在代码中需要一个数据映射器来完成数据转换。如果你不想把你的模型和整个应用交叉使用,这是你要付出的代价)。
以下是图解,大家感受下:

表现层 (Presentation Layer)

表现层在此,表现的是与视图和动画相关的逻辑。这里仅用了一个Model View Presenter(下文简称MVP),但是大家也可以用MVC或MVVM等模式。这里我不再赘述细节,但是需要强调的是,这里的fragment和activity都是View,其内部除了UI逻辑以外没有其他逻辑,这也是所有渲染的东西发生的地方。
本层次的Presenter由多个interactor(用例)组成,Presenter在 android UI 线程以外的新线程里工作,并通过回调将要渲染到View上的数据传递回来。

领域层 (Domain Layer)

这里的业务规则是指所有在本层发生的逻辑。对于Android项目来说,大家还可以看到所有的interactor(用例)实施。这一层是纯粹的java模块,没有任何的Android依赖性。当涉及到业务对象时,所有的外部组件都使用接口。

数据层 (Data Layer)

应用所需的所有数据都来自这一层中的UserRepository实现(接口在领域层)。这一实现采用了Repository Pattern,主要策略是通过一个工厂根据一定的条件选取不同的数据来源。
比如,通过ID获取一个用户时,如果这个用户在缓存中已经存在,则硬盘缓存数据源会被选中,否则会通过向云端发起请求获取数据,然后存储到硬盘缓存。
这一切背后的原理是由于原始数据对于客户端是透明的,客户端并不关心数据是来源于内存、硬盘还是云端,它需要关心的是数据可以正确地获取到。

错误处理

这是一个长期待解决的讨论话题,如果大家能够分享各自的解决方案,那真真是极好的。
我的策略是使用回调,这样的话,如果数据仓库发生了变化,回调有两个方法:onResponse()和onError(). onError方法将异常信息封装到一个ErrorBundle对象中: 这种方法的难点在于这其中会存在一环扣一环的回调链,错误会沿着这条回调链到达展示层。因此会牺牲一点代码的可读性。另外,如果出现错误,我本来可以通过事件总线系统抛出事件,但是这种实现方式类似于使用C语言的goto语法。在我看来,当你订阅多个事件时,如果不能很好的控制,你可能会被弄得晕头转向。
测试

测试方法

关于测试方面,我根据不同的层来选择不同的方法:

展示层 ( Presentation Layer) : 使用android instrumentation和 espresso进行集成和功能测试
领域层 ( Domain Layer) : 使用JUnit和Mockito进行单元测试;
数据层 ( Data Layer) : 使用Robolectric ( 因为依赖于Android SDK中的类 )进行集成测试和单元测试。

代码展示

我猜你现在在想,扯了那么久的淡,代码究竟在哪里呢? 好吧,这就是你可以找到上述解决方案的github链接。还要提一点,在文件夹结构方面,不同的层是通过以下不同的模块反应的:

presentation: 展示层的Android模块
domain: 一个没有android依赖的java模块
data: 一个数据获取来源的android模块。
data-test: 数据层测试,由于使用Robolectric 存在一些限制,所以我得再独立的java模块中使用。

结论

正如 Bob大叔 所说:“Architecture is About Intent, not Frameworks” ,我非常同意这个说法,当然了,有很多不同的方法做不同的事情(不同的实现方法),我很确定,你每天(像我一样)会面临很多挑战,但是遵循这些方法,可以确保你的应用会:

易维护
易测试
高内聚
低耦合

参考资料

Source code: android10/Android-CleanArchitecture · GitHub
The clean architecture by Uncle Bob
Architecture is about Intent, not Frameworks
Model View Presenter
Repository Pattern by Martin Fowler
Android Design Patterns Presentation

Contents
  1. 1. 英文原文:
  2. 2. 中文翻译:
  3. 3. 对应代码:
  4. 4. 开始
  5. 5. 场景
  6. 6. Android应用架构
    1. 6.1. 表现层 (Presentation Layer)
    2. 6.2. 领域层 (Domain Layer)
    3. 6.3. 数据层 (Data Layer)
    4. 6.4. 错误处理
    5. 6.5. 测试方法
    6. 6.6. 代码展示
    7. 6.7. 结论
    8. 6.8. 参考资料