一种更清晰的Android架构

入门指南

我们知道,编写高质量的软件很难,也很复杂:急需要满足需求,又要有稳健性,可维护性,可测试性和灵活性,以适应增长和变化。这就是“干净的架构”出现的地方,在开发任何软件应用程序时可能是一个很好地方法。

这个想法很简单:干净的建筑代表了实践,产生的系统是:

  • 独立于框架
  • 可测试
  • 独立的用户界面
  • 独立的数据库
  • 独立的任何外部结构

不要只用4个圆圈(如图中所示),因为它们只是示意图,但是您应该考虑依赖规则:源代码依赖只能指向内部,并且内圈中得任何东西都不能知道任何关于外圈的事情。

以下是一些与熟悉和理解这种方法的相关名词:

  • 实体:这些是应用程序的业务对象
  • 使用案例:这些使用案例协调实体之间的数据流,也被称为交互者
  • 接口适配器:这组适配器将转换来自用例的实体最方便的格式的数据,也被称为交互者
  • 框架和驱动程序:这是所有细节的地方:UI、工具、框架等

有关更好更广泛地解释,请参阅本文

Android框架

我们从一个简单地场景开始:简单地创建一个小城,显示从服务端中检索到的朋友或用户列表,点击其中的任何一个将打开一个新的界面,显示该用户更多的详细信息。

目的是通过保持业务规则对外界不了解任何事情来区分关注点,从而可以在不依赖任何外部元素的情况下进行测试。

为了达到这个目的,我建议是把项目分成三个不同的层次,每个层次都有自己的职责。

值得一提的时,每一层都是哦那个自己的数据模型,这样就可以实现独立性

image

注意:我没有使用其他的外部库(除了解析json数据的gson和测试用到的junit、mockito、robolectric、espresso),这样使例子更清楚。无论如何,添加ORMs存储磁盘数据或任何依赖注入框架或任何你熟悉的库,可以使开发更轻松愉快。

表现层 (Presentation Layer)

表现层在此,表现的是与视图和动画相关的逻辑。这里仅用了一个Model View Presenter(下文简称MVP),但是大家也可以用MVC或MVVM等模式。这里我不再赘述细节,但是需要强调的是,这里的fragment和activity都是View,其内部除了UI逻辑以外没有其他逻辑,这也是所有渲染的东西发生的地方。

本层次的Presenter由多个interactor(用例)组成,Presenter在 android UI 线程以外的新线程里工作,并通过回调将要渲染到View上的数据传递回来。


mvp

如果你需要一个使用MVP和MVVM的Effective Android UI典型案例,可以参考我朋友Pedro Gómez的文章。

领域层 (Domain Layer)

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

domain

数据层 (Data Layer)

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

![data](http://upload-images.jianshu.io/upload_images/595349-6caa3a650b0f7e7f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240

注:在代码方面,出于学习目的,我通过文件系统和Android preference实现了一个简单、原始的硬盘缓存。请记住,如果已经存在了能够完成这些工作的库,就不要重复制造轮子。

错误处理

这是一个长期待解决的讨论话题,如果大家能够分享各自的解决方案,那真真是极好的。

我的策略是使用回调,这样的话,如果数据仓库发生了变化,回调有两个方法: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” ,我非常同意这个说法,当然了,有很多不同的方法做不同的事情(不同的实现方法),我很确定,你每天(像我一样)会面临很多挑战,但是遵循这些方法,可以确保你的应用会:

  • 易维护 Easy to maintain
  • 易测试 Easy to tes.
  • 高内聚 Very cohesive.
  • 低耦合 Decoupled.

最后,我强烈推荐你去实践一下,并且分享你的经验。也许你会找到更好的解决方案:我们都知道,不断提升自己是一件件非常好的事。我希望这篇文章对你有所帮助,欢迎拍砖。

参考资料

Source code: https://github.com/android10/Android-CleanArchitecture

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

推荐阅读更多精彩内容