Android 项目架构演进

入职安居客三年从工程师到Team Leader,见证了Android团队一路走来的发展历程。所以有心将这些记录下来与你们分享,也算是对本身三年来一部分工做的总结。但愿对你们有所帮助,更但愿能获得你们宝贵的建议。android

1、三网合并

三年前入职时安居客在业务上刚完成了三网合并(新房、二手房、好租和商业地产多个平台多个网站合成如今的[http://anjuke.com],这在公司历史上称之为三网合并),所以app端也将原先的新房、二手房、好租和商业地产多个app合并成为了如今的安居客app。所谓的合并也差很少就是将多个项目的代码拷贝到了一块儿组成了新的Anjuke Project。下面这张图能更加直观的呈现当时的情况。面试

这一时期代码结构混乱、层次不清,各业务技术方案不统一,冗余代码充斥项目的各个角落;甚至连基本的包结构也是胡乱不堪,项目架构更是无从谈起。你们只不过是不停地往上堆砌代码添加新功能罢了。因而我进入公司的第一件事就是向Leader申请梳理了整个项目的结构。数据库

然后随着项目的迭代,咱们不断引入了Retrofit、UniversalImageLoader、OKHttp、ButterKnife等一系列成熟的开源库,同时咱们也开发了本身的UI组件库UIComponent、基础工具库CommonUtils、基于第三方地图封装的MapSDK、即时聊天模块ChatLibrary等等。这以后安居客项目架构大体演变成了由基础组件层、业务组件层和业务层组成的三层架构。以下图:小程序

其中业务层是一种非标准的MVC架构,Activity和Fragment承担了View和Controller的职责:性能优化

前面这种分层的架构自己是没太大问题的,即便到了如今咱们的业务项目也已然是基于这种分层的架构来构建的,只不过在不断的迭代中咱们作了些许调整(分层架构后面在介绍组件化和模块化的时候会详细介绍)。可是随着业务的不断迭代,咱们慢慢发现业务层这种非标准的MVC架构带来了种种影响团队开发效率的问题:网络

  • Activity和Fragment愈来愈多的同时承担了Controller和View的职责,致使他们变得及其臃肿且难以维护;
  • 因为Controller和View的揉合,致使单元测试起来很困难;
  • 回调嵌套太多,面对复杂业务时的代码逻辑不清晰,难以理解且不利于后期维护;
  • 各层次模块之间职责不清晰等等

鉴于三网合并时期我还未加入安居客,因此对这一块的理解不免有误差,若是有安居客的老同事发现文章中的描述有不对的地方还望批评指正。架构

2、由RxJava驱动的MVP架构

一种技术架构没法知足全部的业务项目,更不可能有一种架构方案可以一劳永逸。正如上一节中提到的随着业务的不断迭代,现有架构的缺陷逐渐浮出水面,项目架构必需不断升级迭代才能更好地服务于业务。app

2.1 MVP的设计与实现

在研究了Google推出的基于MVP架构的demo后,咱们发现MVP架构能解决如今所面临过的不少问题,因而咱们学习并引入到了咱们的项目中来,并针对性的作了部分调整。下图呈现的是安居客MVP方案:框架

之前面提到的三层架构的方案来看是这样的:模块化

  • View Layer: 只负责UI的绘制呈现,包含Fragment和一些自定义的UI组件,View层须要实现ViewInterface接口。Activity在项目中再也不负责View的职责,仅仅是一个全局的控制者,负责建立View和Presenter的实例;
  • Model Layer: 负责检索、存储、操做数据,包括来自网络、数据库、磁盘文件和SharedPreferences的数据;
  • Presenter Layer: 做为View Layer和Module Layer的之间的纽带,它从model层中获取数据,而后调用View的接口去控制View;
  • Contract: 咱们参照Google的demo加入契约类Contract来统一管理View和Presenter的接口,使得某一功能模块的接口能更加直观的呈现出来,这样作是有利于后期维护的。

另外这套MVP架构还为咱们带来了一个额外的好处:咱们有了足够明确的开发规范和标准。细致到了每个类应该放到哪一个包下,哪一个类具体应该负责什么职责等等。这对于咱们的Code Review、接手他人的功能模块等都提供了极大的便利。前面提到的[MinimalistWeather]就是为了定规范定标准而开发的。

这一时期咱们还在项目中引入了RxJava,很好的解决了前面提到的嵌套回调的问题,同时可以帮助咱们简化复杂业务场景下的代码逻辑(固然RxJava的好处远远不止这么一点,对RxJava不了解的同窗能够去翻翻我以前[一系列关于RxJava的文章]。咱们也将网络库升级到了Retrofit2+OKHttp3,它们和RxJava之间能更好的配合。

2.2 MVP带来的新问题及解决方案

是否是升级到了MVP架构就高枕无忧了呢?很明显不是这样!MVP架构也会带来如下新的问题:

  • 因为大量的业务逻辑处理转移到了Presenter层,在一些复杂的业务场景中Presenter一样会变得臃肿难懂。细心的同窗可能注意到了前面的架构图中的Model层有个Data Repository模块,Data Repository在这里有两个做用:一是能够将本来由Presenter处理的部分逻辑转移到这里来处理,包括数据的校验、部分单纯只与数据相关的逻辑等等,向Presenter屏蔽数据处理细节,好比做为Presenter就没必要关心Model层传递过来的数据究竟是来至网络仍是来至数据库仍是来至本地文件等等;二是咱们引入了RxJava,可是只有网络层中的Retrofit能返回Observable对象,其余模块都是返回的仍是一些非Observable的Java对象,为了能在整个Presenter层中都体验RxJava带来的美妙之处,所以能够经过Data Repository作一层转换;
  • 如今的MVP架构中最重的部分就是Model Layer了,这一点从前面的架构图中就能体现。所以这就要求咱们在Model层的设计过程当中职责划分要足够清晰,分包更明确,耦合度更低。至于分包你们能够参考[MinimalistWeather]的方案:db包为数据库模块、http包为网络模块、preference包是对SharedPreferences的一些封装、repository包就是前面提到的Data Repository模块;
  • 同时还有一点须要注意,不少人在使用RxJava的过程当中每每忘记了对生命周期的管理,这很容易形成内存泄露。[MinimalistWeather]中采用了CompositeSubscription来管理,你也可使用RxLifecycle这类开源库来管理生命周期。

3、组件化与模块化

去年下半年咱们Android团队内部成立了技术小组,基础组件的开发是技术小组很重要的一部分工做,因此组件化是咱们正在作的事;模块化更多的是现有的方案受到来自业务上的挑战以及受到了Oasis Feng在MDCC上的分享和整个大环境的启发,如今正处于设计规划和demo开发的阶段。

3.1 组件化

组件化不是个新概念,通俗的讲组件化就是基于可重用的目的,将一个大的软件系统拆分红一个个独立组件。

组件化的带来的好处不言而喻:

  • 避免重复造轮子,节省开发维护成本;
  • 下降项目复杂性,提高开发效率;
  • 多个团队公用同一个组件,在必定层度上确保了技术方案的统一性。

如今的安居客有是三个业务团队:安居客用户app、经纪人app、集客家app。为了不各个业务团队重复造轮子,团队中也须要有必定的技术沉淀,所以组件化是必须的。从本篇的第一节你们就能看到组件化的影子,只不过在这以前咱们作的并很差。如今咱们须要提供更多的、职能单1、性能更优的组件供业务团队使用。根据业务相关性,咱们将这些组件分为:基础组件和业务组件。后面在介绍模块化的时候会有进一步的描述。

3.2 模块化

自从Oasis Feng在去年的MDCC2016上分享了模块化的经验后,模块化在Android社区愈来愈多的被提起。咱们天然也不落俗的去作了一些研究和探索。安居客如今面临不少问题:例如全量编译时间太长(我这台13款的MacBook Pro打一次包得花十多分钟);例如新房、二手房、租房等等模块间耦合严重,不利于多团队并行开发测试;另外在17年初公司从新将租房app捡起推广,单独让人来开发维护一个三年前的项目并不划算,因此咱们但愿能直接从如今的安居客用户端中拆分出租房模块做为一个单独的app发布上线。这样看来模块化彷佛是一个不错的选择。

因此咱们作模块化的目的大体是这样的:

  • 业务模块间解耦
  • 单个业务模块单独编译打包,加快编译速度
  • 多团队间并行开发、测试
  • 解决好租App须要单独维护的问题,下降研发成本

15年Trinea还在安居客的时候开发了一套插件化框架,但受限于当时的团队规模而且插件化对整个项目的改造太大,所以在安居客团队中插件化并未实施下来。而模块化实际上是个很好的过渡方案,将项目按照模块拆分后各业务模块间解耦的问题不存在了,后续若有必要,再进行插件化改造只不过是水到渠成的事。

来看看安居客用户app的模块化设计图:

整个项目分为三层,从下往上分别是:

  • Basic Component Layer: 基础组件层,顾名思义就是一些基础组件,包含了各类开源库以及和业务无关的各类自研工具库;
  • Business Component Layer: 业务组件层,这一层的全部组件都是业务相关的,例如上图中的支付组件AnjukePay、数据模拟组件DataSimulator等等;
  • Business Module Layer: 业务module层,在Android Studio中每块业务对应一个单独的module。例如安居客用户app咱们就能够拆分红新房module、二手房module、IM module等等,每一个单独的Business Module都必须准遵照前面提到的MVP架构。

同时针对模块化咱们也须要定义一些本身的游戏规则:

  • 对于Business Module Layer,各业务模块之间的通信跳转采用路由框架Router来实现(可能会采用成熟的开源库,也可能会选择重复造轮子);
  • 对于Business Component Layer,单一业务组件只能对应某一项具体的业务,对于有个性化需求的对外部提供接口让调用方定制;
  • 合理控制各组件和各业务模块的拆分粒度,过小的公有模块不足以构成单独组件或者模块的,咱们先放到相似于CommonBusuness的组件中,在后期不断的重构迭代中视状况进行进一步的拆分
  • 上层的公有的业务或者功能模块能够逐步下放到下层,合理把握好度就好;
  • 各Layer间严禁反向依赖,横向依赖关系由各业务Leader和技术小组商讨决定。

对于模块化项目,每一个单独的business module均可以单独编译成APK。在开发阶段须要单独打包编译,项目发布的时候又须要它做为项目的一个module来总体编译打包。简单的说就是开发时是application,发布时是library。所以须要你在business module的gradle配置文件中加入以下代码:

if(isBuildModule.toBoolean()){
    apply plugin: 'com.android.application'
}else{
    apply plugin: 'com.android.library'
}

若是咱们须要把租房模块打包成一个单独的租房app,像下面这样就好:

咱们能够把Basic Component Layer和Business Component Layer放在一块儿看作是Anjuke SDK,新的业务或者项目只须要依赖Anjuke SDK就好(这一点一样是受到了Trinea文章的启发)。甚至咱们能够作得更极致一些,开发一套本身的组件管理平台,业务方能够根据本身的需求选择本身须要的组件,定制业务专属的Anjuke SDK。业务端和Anjuke SDK的关系以下图所示:

最后看看安居客模块化的总体设计图:

模块化拆分对于安居客这种比较大型的商业项目而言,因为历史比较久远不少代码都运行五六年了;各个业务相互交叉耦合严重,因此实施起来仍是有很大难度的。过程当中不免会有预料不到的坑,这就须要咱们对各个业务有较深的理解同时也要足够的耐心和细致。虽然辛苦,可是一旦完成模块化拆分对整个团队及公司业务上的帮助是很大的。

以上是个人简单总结以及对模块化的一些思考,不足之处还望你们批评指正。后面模块化的demo完善后我会把它放到GitHub,并再出一篇文章详细介绍模块化的设计实现细节。

最后给你们分享一份很是系统和全面的Android进阶技术大纲及进阶资料,及面试题集

想学习更多Android知识,请加入Android技术开发交流 7520 16839

进群与大牛们一块儿讨论,还可获取Android高级架构资料、源码、笔记、视频

包括 高级UI、Gradle、RxJava、小程序、Hybrid、移动架构、React Native、性能优化等全面的Android高级实践技术讲解性能优化架构思惟导图,和BATJ面试题及答案!

群里免费分享给有须要的朋友,但愿可以帮助一些在这个行业发展迷茫的,或者想系统深刻提高以及困于瓶颈的

朋友,在网上博客论坛等地方少花些时间找资料,把有限的时间,真正花在学习上,因此我在这免费分享一些架构资料及给你们。但愿在这些资料中都有你须要的内容。

相关文章
相关标签/搜索