提兵百万西湖上,立马吴山第一峰!这篇文章主要讲述Architecting Android…The clean way?相关的知识,希望能为你提供帮助。
Architecting Android…The clean
way?
原文链接:http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/原文作者:Fernando
Cejas过去几个月,与@pedro_g_s
和
@flipper83
(顺嘴说一下这两位是android开发大牛)两位同行在Tuenti
站点上友好的讨论之后。我觉得这是一个写一篇关于android应用架构的文章的好时机。
写这篇文章的目的是想给大家展现一些我在这几个月所想的加上从研究和实施中学到的一些小方法。
入门指南
我们知道写一款有品质的软件是困难和复杂的:
不仅要满足要求,同一时候也是健壮的、可维护的、可測试的。并且足够灵活适应扩展和变化。这时
“清晰架构”
就出现了,并且可能是一个开发不论什么软件应用的好方法。
这个思路非常easy:清晰架构表示产品系统遵循一组实践原则:
- 框架独立.
- 可測试性.
- UI独立.
- 数据库独立.
- 不论什么外部代理模块独立.
文章图片
不一定非要使用四环结构 (如图所看到的),由于这仅仅是一个原理图,可是你应该考虑依赖原则: 源代码依赖仅仅能向内指向,而且内核中的全部项不能了解不论什么外环的东西。
下面是一些相关的词汇用一个更好的方式熟悉和理解这些方法:
- Entities: 应用的业务对象。
- Use Cases:
结合业务对象的数据流入流出的用例. 相同被称为Interactors。
- Interface Adapters: 这组适配器以最合适的格 式转换用例和业务对象之间的数据。Presenters(表现层) 和 Controllers(控制层)就属于这里。
- Frameworks and Drivers: 这里是详细的实现:UI。工具类, 框架,等等。
我们的场景
我会用一个简单的情景让一切開始:创建一个简单的APP用来显示从云端获取的朋友列表和用户检索。当点击它们的时候。一个新的界面为用户显示具体信息。
我放了个视频在这里。这样你对我所说的有个大概的映像:
Android 架构
目标是 分离关注点。让业务规则对外环事物一无所知,因此,它们在被測试时不须要依赖其他外部元素。
要实现这个目标,我的 建议是将项目分为三层,每个都有自己的目的而且和其他层分开工作。
值 得一提的是,每一层都有自己的数据模型以达到这样的独立性(你会在看到在代码中须要一个数据映射来完毕数据转换,这须要付出一点代价,假设你不想把你的模型和整个应用交叉使用)。
这是图示,你能够感受一下:
文章图片
注意: 我没有使用不论什么外部库(除了用于json数据的解析的gson和用来測试的junit、mockito、robolectric 和espresso)。 原因是它能够使这个样例更清晰。
不管怎样不要犹豫加入ORMs存储数据、依赖注入框架或者你熟悉的不论什么类库,这些都会让你变得更轻松。(记住反复造轮子是不明智的)。
Presentation Layer (表现层)在这里, 表现的是逻辑和视图动画的关联。 这里用了一个Model View Presenter (下称MVP)。可是你也能够用其他不论什么模式。像MVC 或者 MVVM。 我不会在这里具体描写叙述它们,可是这里 fragments and activities 不过views,它们内部除了UI逻辑没有其他逻辑, 这也是全部渲染发生的地方。
在这层的Presenters 由多个 interactors (用例) 组成,在android UI线程之外的新线程运行job,并通过回调将要渲染到view的数据取回。
文章图片
假设你须要一个使用MVP或者MVVM Effective Android UI 的炫酷的样例,能够看看我的朋友 Pedro Gómez 所做的。
Domain Layer (领域层)业务规则定义:全部的逻辑发生在这一层。 对于android项目,你也会看到全部的 interactors (用例) 在这里实现。
这一层是一个纯java的模块,没有不论什么android依赖。
全部的外部组件使用接口訪问业务对象。
文章图片
Data Layer (数据层)应用须要的全部数据来自这一层,通过UserRepository实现(这个接口在 domain layer),使用了 Repository Pattern作为策略, 通过一个 factory 类,依据一定条件下选择不同的数据源。
比如: 通过ID获取用户时。假设这个用户在缓存中已经存在。则硬盘数据会被选中,否则 会从云端获取数据并保存在本地磁盘。
这一切背后的理念是数据源对client是透明的。 client不关心数据来源于内存、磁盘或者云端。它仅仅关系数据会到达和被获取到。
文章图片
注意: 出于学习的目的,这里我实现了一个很easy的代码,使用文件系统和android preferences 实现原始磁盘缓存,再次,假设已经存在能出色完毕这些工作的类库,SHOULD NOT REINVENT THE WHEEL(不要反复造轮子)。
Error Handling (错误处理)
这是一个长期值 得讨论的主题。假设你能够分享你的解决方式那真实太好了。
我的策略是使用回调callbacks, 因此。 假如数据仓库发送改变。回调callback有两个方法 onResponse() 和onError(). 最后封装异常的类叫 “ErrorBundle”: 这样的方法会带来一些困难,由于有一个回调链一个接一个。直到错误到表现层呈现。
可读性会有一点牺牲。
还有一方面。 假设出现错误,我使用event bus 系统抛出错误的事件。可是这类解决方式类似 GOTO,在我看来,当你订阅多个事件但不能非常好的控制。你可能会懵掉。
Testing(測试)
关于測试。我依据不同的层选择了几个解决方式:
- Presentation Layer(展示层):
使用android instrumentation 和 espresso 进行集成和功能測试。
- Domain Layer(领域层):
使用JUnit 加 mockito 进行单元測试。
- Data Layer(数据层): 使用Robolectric (这一层有android依赖) 加junit 加 mockito 进行集成和单元測试。
我猜你在想代码在那里? 好吧,这就是我上面讲到内容的github连接。
关于文件夹结构。提醒一下,不同的层使用模块来表示:
- presentation: 是一个android模块代表展示层。
- domain: 是一个没有android依赖的java模块。
- data: 是一个android模块,全部数据的获取来源。
- data-test:
数据层測试。因为使用Robolectric有一些限制问题,我不得不使用一个单独的模块。
正如Bob大叔所说,“Architecture is About Intent, not Frameworks” 我全然统一这个说法。当然有很多不同的方式做这些事情(不同的实现方式),我非常确信每天你(像我)一样会面临非常多挑战,可是使用上面的方法。能够确保你的应用会:
- 易维护.
- 易測试.
- 高内聚.
- 低耦合.
我希望这篇文章对你有帮助,相同欢迎反馈不允许见。
Source code
- Clean architecture github repository – master branch
- Clean architecture github repository – releases
- Architecting Android..the evolution
- Tasting Dagger 2 on Android
- The Mayans Lost Guide to RxJava on Android
- It is about philosophy: Culture of a good programmer
- The clean architecture by Uncle Bob
- Architecture is about Intent, not Frameworks
- Model View Presenter
- Repository Pattern by Martin Fowler
- Android Design Patterns Presentation
推荐阅读
- android.net.Uri 简介 API
- Android Shape绘制虚线在手机端查看是实线的问题
- Android错误之--Error retrieving parent for item: No resource found that matches the given name &#39
- android boot.img文件结构拆包打包
- 如何在Ubuntu 16.04 LTS上安装NGINX()
- 如何在Ubuntu 160.4 LTS上安装NetBeans()
- 如何在Ubuntu 16.04中安装Magento
- 如何在Ubuntu中安装Laravel
- 如何在Ubuntu上安装LAMP(Linux Apache MySQL PHP)()