技术标签: 组件化 架构 android 模块化 Android
本文已授权微信公众号 AndroidDeveloper 独家发布。
入职安居客三年从工程师到 Team Leader,见证了 Android 团队一路走来的发展历程。因此有心将这些记录下来与大家分享,也算是对自己三年来一部分工作的总结。希望对大家有所帮助,更希望能得到大家宝贵的建议。
三年前入职时安居客在业务上刚完成了三网合并(新房、二手房、好租和商业地产多个平台多个网站合成现在的 anjuke.com,这在公司的历史上称之为三网合并),因此移动端也将原先的新房、二手房、好租和商业地产多个 App 合并成为了现在的安居客 App。所谓的合并也差不多就是将多个项目的代码拷贝到了一起组成了新的 Anjuke Project。下面这张图能更加直观的呈现当时的状况:
这一时期代码结构混乱、层次不清,各业务技术方案不统一,冗余代码充斥项目的各个角落;甚至连基本的包结构也是胡乱不堪,项目架构更是无从谈起。大家只不过是不停地往上堆砌代码添加新功能罢了。于是我进入公司的第一件事就是向 Leader 申请梳理了整个项目的结构。
而后随着项目的迭代,我们不断引入了 Retrofit、UniversalImageLoader、OKHttp、ButterKnife 等一系列成熟的开源库,同时我们也开发了自己的 UI 组件库 UIComponent、基础工具库 CommonUtils、基于第三方地图封装的 MapSDK、即时聊天模块 ChatLibrary 等等。这之后安居客项目架构大致演变成了由基础组件层、业务组件层和业务层组成的三层架构。如下图:
其中业务层是一种非标准的 MVC 架构,Activity 和 Fragment 承担了 View 和 Controller 的职责:
前面这种分层的架构本身是没太大问题的,即使到了现在我们的业务项目也已然是基于这种分层的架构来构建的,只不过在不断的迭代中我们做了些许调整(分层架构后面在介绍组件化和模块化的时候会详细介绍)。但是随着业务的不断迭代,我们慢慢发现业务层这种非标准的MVC架构带来了种种影响团队开发效率的问题:
鉴于三网合并时期我还未加入安居客,所以对这一块的理解难免有偏差,如果有安居客的老同事发现文章中的描述有不对的地方还望批评指正。
一种技术架构无法满足所有的业务项目,更不可能有一种架构方案能够一劳永逸。正如上一节中提到的随着业务的不断迭代,现有架构的缺陷逐渐浮出水面,项目架构必需不断升级迭代才能更好地服务于业务。
在研究了 Google 推出的基于 MVP 架构的 Demo 后,我们发现 MVP 架构能解决现在所面临过的很多问题,于是我们学习并引入到了我们的项目中来,并针对性的做了部分调整。下图呈现的是安居客 MVP 方案:
以前面提到的三层架构的方案来看是这样的:
基于此架构我在 GitHub 上开源了一个项目MinimalistWeather,有兴趣的小伙伴可以去 Clone 下来看看,如果觉得对你有帮助就给个 Star 吧。 :)
另外这套MVP架构还为我们带来了一个额外的好处:我们有了足够明确的开发规范和标准。细致到了每一个类应该放到哪个包下,哪个类具体应该负责什么职责等等。这对于我们的 Code Review、接手他人的功能模块等都提供了极大的便利。前面提到的 MinimalistWeather 就是为了定规范定标准而开发的。
这一时期我们还在项目中引入了 RxJava,很好的解决了前面提到的嵌套回调的问题,同时能够帮助我们简化复杂业务场景下的代码逻辑(当然 RxJava 的好处远远不止这么一点,对 RxJava 不了解的同学可以去翻翻我之前一系列关于 RxJava 的文章)。我们也将网络库升级到了 Retrofit2 + OKHttp3,它们和 RxJava 之间能更好的配合。
是不是升级到了 MVP 架构就高枕无忧了呢?很明显不是这样!MVP 架构也会带来以下新的问题:
去年下半年我们 Android 团队内部成立了技术小组,基础组件的开发是技术小组很重要的一部分工作,所以组件化是我们正在做的事;模块化更多的是现有的方案受到来自业务上的挑战以及受到了 Oasis Feng 在 MDCC 上的分享和整个大环境的启发,现在正处于设计规划和 Demo 开发的阶段。
组件化不是个新概念,通俗的讲组件化就是基于可重用的目的,将一个大的软件系统拆分成一个个独立组件。
组件化的带来的好处不言而喻:
现在的安居客有是三个业务团队:安居客用户 App、经纪人 App、集客家 App。为了避免各个业务团队重复造轮子,团队中也需要有一定的技术沉淀,因此组件化是必须的。从本篇的第一节大家就能看到组件化的影子,只不过在这之前我们做的并不好。现在我们需要提供更多的、职能单一、性能更优的组件供业务团队使用。根据业务相关性,我们将这些组件分为:基础组件和业务组件。后面在介绍模块化的时候会有进一步的描述。
自从 Oasis Feng 在去年的 MDCC2016 上分享了模块化的经验后,模块化在 Android 社区越来越多的被提起。我们自然也不落俗的去做了一些研究和探索。安居客现在面临很多问题:例如全量编译时间太长(我这台13款的 MacBook Pro 上打一次包得花十多分钟);例如新房、二手房、租房等等模块间耦合严重,不利于多团队并行开发测试;另外在17年初公司重新将租房 App 捡起推广,单独让人来开发维护一个三年前的项目并不划算,所以我们希望能直接从现在的安居客用户端中拆分出租房模块作为一个单独的 App 发布上线。这样看来模块化似乎是一个不错的选择。
所以我们做模块化的目的大致是这样的:
15年 Trinea 还在安居客的时候开发了一套插件化框架,但受限于当时的团队规模并且插件化对整个项目的改造太大,因此在安居客团队中插件化并未实施下来。而模块化其实是个很好的过渡方案,将项目按照模块拆分后各业务模块间解耦的问题不存在了,后续如有必要,再进行插件化改造只不过是水到渠成的事。
来看看安居客用户 App 的模块化设计图:
整个项目分为三层,从下往上分别是:
同时针对模块化我们也需要定义一些自己的游戏规则:
对于模块化项目,每个单独的 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,并再出一篇文章详细介绍模块化的设计实现细节。
参考资料:
如果你喜欢我的文章,就关注下我的知乎专栏或者在 GitHub 上添个 Star 吧!
文章浏览阅读6.3k次。日志默认info级别debug日志不会打印,但是会执行日志填充的数据例如:logger.debug("日志输出",2*10); 1. 2*10会先执行出结果,然后继续往下走2. 在ch.qos.logback.classic.Logger#filterAndLog_1方法中判断是否符合级别要求是否需要输出3.如图:..._debug中的计算是否在info级别也会跑
文章浏览阅读1.4k次。Similarly to the previous example, let us apply our calibration engine onto the data that comes with the originalcalibration toolbox of Heikkil� from the University of Oulu. Once again. do not bothe_non-planar calibration
文章浏览阅读1w次,点赞10次,收藏63次。物联网常用的网络协议:MQTT、AMQP、HTTP、CoAP、LwM2M物联网设备间沟通的语言,就是网络协议。设备间想相互交流,通信双方必须使用同一种“语言”。比如说你和中国人问好说’你好‘、日本人问好要说‘こんにちは’、和英国人问好要说‘hello’.说起网络协议,你可能马上就想到了 HTTP 协议。是的,在日常的 Web 开发中,我们总是需要跟它打交道,因为 HTTP 协议是互联网的主流网络协议。类似地,应用在互联网中的网络协议,还有收发电子邮件的 POP3 、SMTP 和 IMAP 协议,以及_lmm2m和mqtt
文章浏览阅读7.4k次,点赞4次,收藏20次。这篇博文简要记录一下使用MKL函数库计算一般矩阵的特征值与特征向量对形如对称矩阵或是埃尔米特等特殊矩阵有其对应的子程序,在这里先不涉及。有需求的可以自行查阅MKL官方文档下面给出本次示例代码:代码使用f95接口。f77借口参数太多,笔者太懒<不过懒惰是创新的原动力^_^>program testGeev use lapack95 implicit..._fortran求矩阵特征值
文章浏览阅读147次。学习内容来自:Numpy Tutorial文章目录Array SlicingArray IndexingMathematical ManipulationBroadcastingImage Processing基本的用法课程里面说的挺详细了。 特别记录一些需要关注的点。Array Slicing使用固定数字进行array寻址会导致数组降维。y = np.random.random((3,..._np.imresize
文章浏览阅读355次。题目阅览 观察数字:12321,123321 都有一个共同的特征,无论从左到右读还是从右向左读,都是相同的。这样的数字叫做:回文数字。 本题要求你找到一些5位或6位的十进制数字。满足如下要求: 该数字的各个数位之和等于输入的整数。 输入格式 一个正整数 n (10<n<100), 表示要求满足的数位和。 输出格式若干行,每行包含一个满足要求的5位或6位整数。 数字按从小到大的顺序排列。 如果没有满足条件的,输出:-1样例输入144样例输出199899_c++蓝桥杯 回文数
文章浏览阅读6.2k次,点赞3次,收藏13次。需要的pom文件 <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.1.0</version>_java扫二维码进入自己制作的网页
文章浏览阅读650次。在遥感图像处理中,我们经常需要将多波段遥感影像拆分成多个单波段图像,以便进行各种分析和后续处理。本篇博客将介绍一个用Python编写的程序,该程序可以读取多波段遥感影像,将其拆分为单波段图像,并保存为单独的文件。本程序使用GDAL库来处理遥感影像数据,以及NumPy库来进行数组操作。结果如下图所示,选中的影像为输入的多波段影像,其他影像分别为拆分后的多波段影像。_一个多波段影像分解成多个单波段影像
文章浏览阅读5.1k次,点赞2次,收藏4次。0前言一直用的好好的移动硬盘突然不显示了,前段时间因为比较忙,一直没顾得上管它,趁这个假期,好好捅咕了一番,总算是弄好了,特此将解决的过程记录如下:1.问题描述 1.我的移动硬盘在其他人的电脑上能够正常显示和使用 2.其他移动硬盘在我电脑上能够正常的显示和使用 3.在我的电脑上,该移动硬盘,既不显示盘符,磁盘管理 又不显示该磁盘2.问题分析1.我的移动硬盘能够在其他人电脑上_电脑无法显示移动硬盘
文章浏览阅读1k次。Kernel initialization. Part 10.在原文的基础上添加了5.10.13部分的源码解读。End of the linux kernel initialization processThis is tenth part of the chapter about linux kernel initialization process and in the previous part we saw the initialization of the RCU and stopped o_linux 标志着kernel启动完成
文章浏览阅读5.3k次,点赞5次,收藏23次。Scala语言概述:Scala语言是一门以Java虚拟机为运行环境,支持面向对象和函数式编程的静态语言,java语言是面向对象的,所以代码写起来就会相对比较模块儿,而函数式编程语言相对比较简洁_scala安装及环境配置
文章浏览阅读2.4k次。“他来听我的演唱会,门票换了手铐一对”。最近歌神张学友变阿SIR,演唱会上频频抓到罪犯,将人脸识别技术又一次推到了大众的视线中。要说人脸识别技术的爆发,当属去年9月份苹果iPhone x的发布,不再需要指纹,只需要扫描面部就可以轻松解锁手机。任何技术一旦进入智能手机这个消费市场,尤其是被苹果这个标志性的品牌采用,就意味着它将成为一种趋势,一个智能设备的标配。在智能手机快速崛起的这几年,其密码锁..._人脸识别发展历史