1. 基础架构:
使用Android studio开发时,根据依赖原则,用最简单的线性架构来接耦:
- 使用Base module引入多种工具库;
- 使用Framework module编写框架逻辑,可以被持续复用;
- 将业务集中到Common module中以保持业务高内聚,利用文件夹来区分不同的业务间的关联,一个文件夹作为一个独立业务。
- app module被编译打包生成app。
基础架构的业务保持高内聚,但是实现的规则往往比较随意,对代码质量的限制也不高。如没规范性使用设计模式接口进行解耦,而开发人员维护随意,就会使业务间代码耦合度越来越高。特别是产品需求不定向时,其兼容性后续开发的实现如没有遵循统一规范,就会让业务实现/添加/移除的难度增大。
2. 基础组件化:
组件化需要遵循的基本规则,表达了简单的分层结构,而且使用了树形结构来解析开发规则。
- Base module集成了工具库和封装框架;
- 组件层中的每个组件代表一个业务;
- app module统筹整个app的集成层,最终被编译打包成app。
这种简洁的组件化工程架构比较适合中小型开发项目,其包含了基础组件,如数据库/图片等,均为轻量级封装。业务层的每个模块互相独立,因为页面逻辑简介,单独的页面划分单一的功能模块,只需一个Base module就可以完成基础工具库依赖。
3. 模块化:
随着业务量的增加,基础模块层逻辑越来越复杂。基础层需要更加细分,重新划分为组件层和基础库层。以业务模块划分模块层,模块层依赖于组件层,组件层提供功能逻辑推动业务研发。
- 应用层:生成app和加载初始化操作;
- 模块层:每个模块相当于一个业务,通过module来分隔每个业务的逻辑,一个模块由多个不同的页面逻辑组成;
- 基础层:基础组件的整合,提供基础组件能力给业务层使用;
- 组件层:将图片加载/网络http/socket等基础功能划分为一层;
- 基础库层:更加基础的库类依赖,此层非必须,例如RxJava/EventBus等一些代码结构优化的库,还有自己编写的封装类。
基础库层可以转移到基础层和组件层中,这样可以减少层级。
基础层可以只是一个空壳,起到隔离模块层和组件层的入口的作用,可以作为中转,封装一些必须使用的组件功能,隐藏一些实现细节。
模块层的业务逻辑需要业务之间的信息交互和转发的实现。
这个结构适合中型app的搭建,当业务需要重新细分重构时,可以考虑使用这种架构方式。这种架构要求组件独立复用,模块能够不依赖于其他模块实现。
4. 多模板化:
多模板化就是融合了组件化分发后演化而来的架构。
在模块化的前提下,使用组件分发,单页面中分发出多个独立的业务。
模板层服务于多个分发业务的组装。在模板层中,一个模版包含了多种业务,一个页面可以使用多种模版的逻辑。如直播间和QQ聊天室,当有多个特别模版的布局组装和位置变更时,就需要配置模版。
多模版化的产品要求样式多变,其衍生出的架构演变是模块化进行的一个方向。
5. 插件化:
业务层相对独立后,分层已经非常稳定时。
- 组件层中需要添加插件框架,如Small/Atlas/RePlugin等,根据项目情况作出选型,选型调研尤为重要。
- 模块层的每个模块是以业务是否独立作为划分的条件,如地图/直播间/活动/第三方嵌入等,作为单独的研发分支(svn/git工程)。每个模块作为基础项目研发,模块间互相独立,项目达到最大程度接耦。
- 应用层对应插件化宿主app,一些非常基础的业务如登陆/支付等需要账号的模块最好集成到这里。
这样的架构适合多个业务动态迭代。一个小组可以负责一个业务工程,脱离原来宿主工程的研发。但是需要注意,小心设置base module中业务模块间的通信机制,还有模块页面的跳转/资源重叠及混淆问题。
在插件化研发阶段还需要考虑一些问题:
- 解决资源冗余,包括对base module的依赖和库依赖。
- 资源混淆和资源冲突。
- 插件加载方式。
- 通信依赖/数据交互/事件机制。
6. 进程化:
当app越来越大时,一个app占用几百MB以上的空间,几乎需要使用Android开发的全部功能。如何让系统给app分配更大内存,更加流畅地运行,应用开发的架构指向进程化。
Android系统不是以app为单位分配内存的,而是以进程为单位限制内存和资源分配的。那么开启多个进程会使app获得更多的内存,运行更加流畅。多进程使内存分散,既避免了让单进程太大导致内存过大,在不断回收内存中导致卡顿的问题,也避免了因内存过低被系统杀死。
进程层是以非常大的功能业务划分条件,如播放视频/拍照/播放音乐/地图等非常消耗内存的模块。
进程化不仅能解决OOM问题,还能合理有效利用内存,在单一进程奔溃的时候,并不影响这个应用的使用。
跨进程的通信和交互比组件化/模块化更加复杂。Android系统对隔离进程比Android studio隔离模块要严格得多。系统隔离模块则是在开发中隔离。通信需要用到跨进程通信的AIDL,或者是其他块进程方式。
使用进程化需要注意:
- 静态成员和单例模式会失效,因为进程内存空间互相独立,所以虚拟机内的静态方法区分的静态变量也是互相独立的。由于单例模式基于静态变量的,因此单例模式会失效。
- 线程同步机制完全失效,由于Java的同步机制是使用虚拟机来进行调度的,因而两个进程拥有两个虚拟机,同步在多进程中也是无效的,synchronize/volatile等都是基于虚拟机级别的同步。
- SharePreference的可靠性下降,SharePreference没有对多进程的支持。
- 文件读写的时候,需要考虑并发访问文件的问题。不同进程访问同一个文件是没有进程锁机制的。SQLite很容易被锁,其他进程访问时就会报出异常。
- application多次创建。每个进程在创建时都会新建一个application,多进程会面临application被多次创建的问题。每个application都会执行onCreat方法。只能通过进程名来区分不同的进程,进行不同进程的初始化操作。
使用进程开发需要了解Android系统的虚拟机机制,了解系统进程回收的情况。