安卓架构...有什么清晰的方式?

安卓架构...有什么清晰的方式?

前言

我们知道写出有质量的软件是复杂而且困难的:它不仅仅在于满足所有的需求,同时也应该是健壮的、易于维护的、方便测试的、非常灵活的(能够灵活的改变内容,如模块加减)。清晰的架构(The Clean Architecture)就是在这种需求下诞生,而且能够成为在软件开发过程中的一个好的选择。

清爽的架构的想法非常简单:它代表一组方式规则,能够产生如下的系统:

  • 与框架无关
  • 易于测试
  • 与UI无关
  • 与数据库无关
  • 与其他外部组件无关

在实际应用过程中,没有必要像图中那样来进行划分,因为上图只是概要图。但是应该做到单向依赖:代码的依赖性只能够向内, 所有内部的模块不应该知道任何外部模块的信息,更不要说有任何调用。

下面是一些相关词汇,用来帮助理解:

  • 实例(Entities): 这些是软件实现过程中的业务实例(Object)。
  • 数据交互器(Use Cases,又称interactor):
    数据交互器负责协调实例的数据传输。
  • 接口适配器(Interface Adapters): 接口适配器负责数据转换,将从实例和数据交互器中传递出来的数据进行解析。Presenter和Controller就属于这里。  (从原文中可以理解,在设计usecase 和entities的时候,尽量让这两层的数据变得简单、易于使用,提升这两层的效率。这样,将更深层中的工作量变得更少。只是个人理解。)
  • 框架和驱动(Frameworks and Drivers):  这一部分负责所有相关细节,如: UI, 工具,框架等(这里暂时无法理解)。

需要更加清晰的理解,可以翻墙看下链接中的视频。

安卓架构

架构的目的是分离原则:内部的业务逻辑完全与外部无关,因此,在测试中就不需要加载外部依赖。

为了实现这个目标,我建议将程序分成三层,其中每一层有自己的工作,并且在运行过程中与其它层隔离开来。

值得一提的是,通过为每一层建立自己的数据模型,能够实现各层独立。(在代码中你会发现,需要用data mapper来实现数据转换,作为代价,你的model将横跨整个APP。)

上面内容的图解:

注: 我没有用任何外部库(除了Gson来解析json数据,和junit,mockito,robolectric,espresso用来测试)。这样,我就能把例子弄得更加清楚。但是,千万不要自己重新去写一个轮子,能从别人那儿拿来用的就从别人那拿(你要好好挑一挑)。

展示层(Presentation Layer)

与页面逻辑和页面动画相关的逻辑在这一层中。它主要用的是MVP架构。你也可以按照需要使用MVC,MVVM等。值得强调的是,在展示层,fragment和activity仅仅是View,其中没有任何除了UI逻辑以外的逻辑,同时渲染也在这一层被实现。

Presenter在这一层中与数据交互器(interactor,use case)一起以新线程(UI线程外)的方式工作,然后通过回调函数将需要展示的数据交给View。

逻辑层(Domain layer)

本层业务规则为: 所有的逻辑在这一层发生。在项目层面,你会发现所有的数据交互器在这一层被实现。

这一层为纯java模块,不包括任何对android的依赖。所有的层外组件通过接口与逻辑层中的实例(Object)交互。

数据层(Data Layer)

数据层就像一个仓库一样,所有APP需要的数据都通过位于逻辑层中的仓库接口(Repository interface)被取出。这个接口使用了仓库模式,也就是,通过一个工厂,按需挑选出各种数据向上传递。打个比方,当通过id获取用户的时候,程序会判断缓存中是否有用户数据,如果没有的话,从服务器中获取,并存在本地,如果有的话,直接从缓存中获取。

用这种方式的原因是:用户不在乎数据的来源是什么,他们只在乎数据是否被获取到。

注意:代码中有这一接口的简单例子。还是那句话,不要重新做轮子。

错误处理

我的策略是使用回调函数,因此,比如在数据仓库中有情况发生,将产生两个回调函数,onResponse()和onError()。后者将把异常打包进入一个叫做“ErrorBundle”的包装类: 这个方式带来了一定的问题,因为这样产生了一连串的,一层层上报的回调函数,直通展示层,被展示层处理掉。这种方式在一定程度上降低了代码可读性。

另一方法是,我可以实现EventBus,每次有错误发生,EventBus将会将时间分配给指定处理函数。但是这样需要非常严谨,小心的处理,否则会不好管理。

测试

关于测试,我给出一点建议。

  • 展示层:使用安卓自动化测试工具instrumentation和espresso来实现集成和功能性测试。
  • 逻辑层:使用Junit 和 mockito来进行单元测试。
  • 数据层:Robolectric(因为本层有安卓依赖)和junit以及mockito来进行测试。

结论

架构的设计是以实际情况为走向,而不是框架。要根据实际情况来进行架构设计。在设计架构的时候要确保:

  • 易于维护
  • 方便测试
  • 高内聚
  • 低耦合

代码例子: 参见github

时间: 2024-08-30 10:37:18

安卓架构...有什么清晰的方式?的相关文章

安卓架构设计

先上一张总图,这是一张较为完整的安卓平台架构图,从上层到底层共包括四层,分别是应用程序程序层.应用框架层.系统库和Android运行时和Linux内核. 蓝色的代表java程序,黄色的代码为运行JAVA程序而实现的虚拟机,绿色部分为C/C++语言编写的程序库,红色的代码内核(linux内核+driver).在Application Framework之下,由C/C++的程序库组成,通过JNI完成从JAVA到C的调用. 我主要负责 应用程序层(application),这层的内容比较少, Andr

linux驱动程序之电源管理之新版linux系统设备架构中关于电源管理方式的变更

新版linux系统设备架构中关于电源管理方式的变更 based on linux-2.6.32 一.设备模型各数据结构中电源管理的部分 linux的设备模型通过诸多结构体来联合描述,如struct device,struct device_type,struct class, struct device_driver,struct bus_type等. @kernel/include/linux/devices.h中有这几中结构体的定义,这里只列出和PM有关的项,其余查看源码: struct d

visio图片导入word和PPT的最清晰的方式

在visio中画图之后,要导入PPT和Word,一般情况下我选择的是先导出为JPG或者PNG格式的图片,然后再插入到Word和PPT中,但是这样往往不清楚,今天发现一个很方面而且很清楚的方式,那就是: 在viso的编辑界面画好图之后, 直接ctrl+a全选, 然后ctrl+c复制,再 ctrl+v粘贴到world或者PPT中, 图片非常清晰! visio图片导入word和PPT的最清晰的方式

Linux進取之旅2: 一个最基本的 LVS负载均衡架构及配置(NAT路由方式)

平台及环境: LVS1:    srv1.training.cc                       private_IP: 172.25.31.20/24    pub_IP :10.0.0.20/24    OS=rhel6.5 private_Virtual IP: 172.25.31.99/32       pub_Virtual IP:10.0.0.99/32 realserver1 :    srv2.training.cc             private_IP:17

大数据架构的典型方法和方式

大量的IT组织如今都已自己的数据架构,因为都依赖于传统的数据架构.处理多数据源已不再新鲜:这些架构已经连接了多维度的数据源例如 CRM 系统,文件系统和其他商用系统.主要运行的关系型数据库有 Oracle, DB2和Microsoft SQL. 如今,一般的数据分析周期是运行一些周期性脚本直接从数据库提取和处理数据.这些主要由 ETL工具如 Informatica 或者 Talend. 目标是将这些提炼的数据加载到数据仓库用于将来的分析. 不幸的是,这一方法在周期结束后可能不适合商务的需要了.这

互联网(腾讯)p7安卓架构师近十年核心资料免费分享

最近整理了一份安卓开发的核心知识点(部分源码).包含了UI工程师,Android底层开发工程师,Android部分架构,原生性能优化及混合优化,大厂面试):以及最新的flutter专精技术知识点.**如果需要获取到这个[核心知识点整理]文档的请入圈(面向全体Android开发人员)https://jq.qq.com/?_wv=1027&k=5MQDHG8 由于细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容! 源码文档 摘选部分kotlin当然还有实战部分

安卓HTTP访问的两种方式

转自:http://blog.sina.com.cn/s/blog_87216a0001014sm7.html 使用HttpClient: NameValuePair nameValuePair1 = new BasicNameValuePair("name", "yang"); NameValuePair nameValuePair2 = new BasicNameValuePair("pwd","123123"); Lis

安卓动画两种基本实现方式

1.代码实现混合动画的方式,这里用到了AnimationSet这个Animation的子类来实现,从底层看该类实现了Animation的大多数方法,构造函数也有好几个. AnimationSet animationSet = new AnimationSet(true);//这里的ture表示所有的动画都使用同一变速器,也就是在布局文件中的set里设置shareInterpolator="true" AlphaAnimation alphaAnimation = new AlphaAn

安卓程序防止反编译的方式

1. 加壳 apk的加壳:在程序外面再包裹一层代码,保护里面的代码不被非法修改或者反编译. 被保护的程序用加密算法加密,解密逻辑写在作为壳的APK中,实际执行的是被保护的程序. 大多是通过DexClassLoader或者隐藏的函数openDexFile将源dex(即被保护的app)加载进来,然后动态替换Application来启动源程序.跟Windows上传统的PE文件加壳有一定区别. 要破解传统的壳,需要跟踪控制流找到OEP,然后把源程序从内存中dump下来,重建输入表,最困难的就是要跟着外壳