在Android SDK一文中,咱们谈到模块化和组件化,现在咱们来聊聊组件化开发背后的哪些事.最先是在广告SDK中应用组件化,但是相同适用于普通应用开发前端
如下高能,请作好心理准备,看不懂请发私信来交流.本文不推荐新手阅读,假设你刚接触Android开发不久,请立马放弃阅读本文.android
组件化不是个新概念,其在各行各业都一直备受重视.至于组件化何时在软件project领域提出已经无从考究了,只是呢可以确认的是组件化最先应用于服务端开发,后来在该思想的指导下,前端开发和移动端开发也产生各自的开发方式.web
在了解组件化以前,先来回想下模块化的定义bash
Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality.markdown
简单来讲,模块化就是将一个程序依照其功能作拆分,分红相互独立的模块,以便于每个模块仅仅包括与其功能相关的内容。模块咱们相对熟悉,比方登陆功能可以是一个模块,搜索功能可以是一个模块,汽车的发送机也但是一个模块.网络
现在来看看”组件化开发”,这里咱们看一下其定义:架构
Component-based software engineering (CBSE), also known as component-based development (CBD), is a branch of software engineering that emphasizes the separation of concerns in respect of the wide-ranging functionality available throughout a given software system. It is a reuse-based approach to defining, implementing and composing loosely coupled independent components into systems. This practice aims to bring about an equally wide-ranging degree of benefits in both the short-term and the long-term for the software itself and for organizations that sponsor such software.app
通俗点就是:组件化就是基于可重用的目的,将一个大的软件系统依照分离关注点的形式,拆分红多个独立的组件,已较少耦合。ide
咋样一看仍是很是抽象,说了这么多好像仍是不明白.什么是组件呢?模块化
组件可以是模块、web资源,软件包,比方汽车的发动机是一个模块,也是一个组件,再或者前端中的一个日历控件是一个模块,也一个组件.
当你看到这的时候,想必心理一阵恶寒:模块化?
组件化?到底是什么鬼?有啥差异.
有这样的感受才是对的,模块化和组件化本质思想是同样的,都是”大化小”,二者的目的都是为了重用和解耦,仅仅是叫法不同.假设非要说差异,那么可以以为模块化粒度更小,更側重于重用,而组件化粒度稍大于模块,更側重于业务解耦.
组件化开发的优势是显而易见:系统级的控制力度细化到组件级的控制力度,一个复杂系统的构建最后就是组件集成的结果.每个组件都有本身独立的版本号,可以独立的编译,測试,打包和部署
产品组件化后可以实现完整意义上的按需求进行产品配置和销售,用户可以选择使用那些组件,组件之间可以灵活的组建.
配置管理,开发,測试,打包,公布全然控制到组建层面,并带来很是多优势.比方一个组件小版本号进行升级,假设对外提供的接口没有发生不论什么变化,其它组件全然不需要再进行測试.
但是组件化的实施对开发者和团队管理者提出了更高水平的要求.相对传统方式,在项目的管理和组织上难度加大,要求开发者对业务有更深层次上的理解.
为何要在Android中实行组件化开发呢,其根本缘由在于业务的增加提升了项目的复杂性,为了更好的适应团队开发,提升开发效率,实行组件化乃大势所趋.
为了更好的帮助你们理解上面这句话,我将从最先的Android 项目开发方式提及.
所谓的简单开发模型是最基础的开发方式,project中没有所谓的模块,没有所谓的规划,常见于刚開始学习的人学习阶段或者是我的学习过程所写的demo,其结构大概例如如下:
不难发现,每每是在一个界面中存在着大量的业务逻辑,而业务逻辑中充斥着各类各类网络请求,数据操做等行为,整个项目中没有所谓的模块的概念,项目组成的基本单位不是模块,而是方法级的.
关于这样的开发模型没什么需要介绍的,咱们早期都经历过,现在除了很是少很是古老的项目以及刚開始学习的人练手之做,已经很是少见到.
该种开发模型已经有了明白的模块划分,并且经过逻辑上的分层呈现出较好结构,该模型最为咱们所熟悉,通常用于早期产品的高速开发,团队规模较小的状况下.该种开发模型结构例如如下:
随着产品的迭代,业务愈来愈复杂,随之带来的是项目结构复杂度的极度添加,此时咱们面临着几个问题:
在面临这些问题的前提下,咱们又一次来思考组件化,看看它可否解决咱们在Android 项目开发中所遇到的难题.
借助组件化这一思想,咱们在”单project”模型的基础上,将业务层中的各业务抽取出来,封装成对应的业务组件,将基础库中各部分抽取出来,封装成基础组件,而主project是一个可执行的app,做为各组件的入口(主project也被称之为壳程序).这些组件或以jar的形式呈现,或以aar的形式呈现.主project经过依赖的方式使用组件所提供的功能.
(需要注意这是理想状态下的结构图,实际项目中,业务组件之间会产生通讯,也会产生依赖,关于这一点,咱们在下文会谈)
不管是jar仍是aar,本质上都是Library,他们不能脱离主project而单独的执行.当团队中成员共同參与项目的开发时,每个成员的开发设备中必须至少同一时候具有主project和各自负责组件,不难看出经过对项目实行组件化,每个成员可以专一本身所负责的业务,并不影响其它业务,同一时候借助稳定的基础组件,可以极大下降代码缺陷,于是整个团队可以以并行开发的方式高效的推动开发进度.
不但如此,组件化可以灵活的让咱们进行产品组装,要作的无非就是依据需求配置对应的组件,最后生产出咱们想要的产品.这有点像玩积木,经过不一样摆放,咱们就能获得本身想要的形状.
对測试同窗而言,能有效的下降測试的时间:原有的业务不需要再次进行功能測试,可以专一于发生变化的业务的測试,以及终于的集成測试就能够.
到现在为止,咱们已经有效攻克了”单project开发模型”中一些问题,对于大部分团队来讲这样的已经可以了,但是该模型仍然存在一些可以改进的点:每次改动依赖包,就需要又一次编译生成lib或者aar.比方说小颜同窗接手了一个项目有40多个组件,在最后集成所有组件的时候,小颜同窗发现当中某组件存在问题,为了定位和改动该组件中的问题,小颜同窗不断这调试该组件.由于在该模型下,组件不能脱离主project,那么意味着,每次改动后,小颜同窗都要在漫长的编译过程当中等待.更糟糕的是,现在离上线仅仅有5小时了,每次编译10分钟,为改这个bug,编译了20次,恩….什么也不用干了,可以提交离职报告了
怎样解决这样的每次改动组件都要连同主project一块儿编译的问题?如下咱们来看主project多子project开发模型是怎样解决该问题的.
该种开发模型在”主project多组件”开发模型的基础上作了改进,其结构图例如如下:
不难发现,该种开发模型在结构上和”主project多组件”并没有不一样,惟一的差异在于:所有业务组件再也不是mouble而是做为一个子project,基础组件可以使moudle,也可以是子project,该子project和主project不一样:Debug模式下下做为app,可以单独的开发,执行,调试;Release模式下做为Library,被主project所依赖,向主project提供服务.
在该种模型下,当小颜同窗发现某个业务组件存在缺陷,会怎样作呢?
比方是基础组件2出现故障,由于在Debug模式下,基础组件2做为app可以独立执行的,所以可以很是easy地对该模块进行单独改动,调试.最后改动完后仅仅需要又一次编译一次整个项目就能够.
不难发现该种开发模型有效的下降了全编译的次数,下降编译耗时的同一时候,方便开发者进行开发调试.
对測试同窗来讲,功能測试可以提早,并且可以及时的參与到开发环节中,将风险降到最低.
到现在,咱们在理论层次上讲明了採用组件化开发给咱们带来的便利,空口无凭是没有说服力的,在如下的一小节中,咱们来谈谈怎样组件化在Android中的实施过程.
组件化首要作的事情就是划分组件.怎样划分并无一个确切的标准,我建议早期实施组件化的时候,可以以一种”较粗”的粒度来进行,这样左右的优势在于后期随着对业务的理解进行再次细分,而不会有太大的成本.固然,我建议划分组件这一工做有团队架构人员和业务人员协商定制.
在”主project多子project模型”中,咱们提到子project在Debug模式下作为单独的Application执行,在Release模式下做为Library执行,怎样去动态改动子project的执行模式呢?咱们都知道採用Gradle构建的project中,用apply plugin: 'com.android.application'
来标识该为Application,而apply plugin: 'com.android.library'
标志位Library.所以,咱们可以在编译的是同经过推断构建环境中的參数来改动子project的工做方式,在子project的gradle脚本头部加入如下脚本片断:
if (isDebug.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
除此以外,子project中在不一样的执行方式下,其AndroidMainifest.xml也是不相同的,需要为其分别提供本身AndroidManifest.xml文件:在子projectsrc文件夹下(其它位置建立)建立两个文件夹,用来存放不一样的AndroidManifest.xml,比方这里我建立了debug和release文件夹
接下来相同需要在该子project的gradle构建脚本中依据构建方式制定:
android {
sourceSets {
main {
if(isDebug.toBoolean()) {
manifest.srcFile 'src/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/release/AndroidManifest.xml'
}
}
}
}
在”主project多组件”这样的理想模型下业务组件是不存在相互通讯和依赖的,但现实倒是相反的,例如如下图:
这里,业务组件1和业务组件3同一时候向业务组件2提供服务,即业务组件2需要同一时候依赖业务组件3和业务组件1.
现在咱们再来看一种更糟糕的状况:
由此看来,在业务复杂的状况下,组件与组件之间的相互依赖会带来两个问题:
先来解决业务组件通讯问题.当年看到上面那张复杂的组件通讯图时,咱们不难想到操做系统引入总线机制来解决设备挂载问题,相同,借用总线的概念咱们在project加入”组件总线”,用于不一样组件间的通讯,此时结构例如如下:
所有挂载到组件总线上的业务组件,都可以实现双向通讯.而通讯协议和HTTP通讯协议类似,即基于URL的方式进行.至于实现的方式一种可以基于系统提供的隐式意图的方式,还有一种则是全然自行实现组件总线.这篇文章不打算在此不作具体说明了.
对于採用aar方式输出的Library而言,在构建项目时,gradle会为咱们保留最新版本号的aar,换言之,假设以aar的方式向主project提供提供依赖不会存在反复依赖的问题.而假设是直接以project形式提供依赖,则在打包过程当中会出现反复的代码.解决project反复依赖问题眼下有两种作法:1.对于纯代码project的库或jar包而言,仅仅在终于项目中执行compile,其它状况採用provider方式;2.在编译时检測依赖的包,已经依赖的再也不依赖
在合并多个组件到主project中时,可能会出现资源引用冲突,
最简单的方式是经过实现约定资源前缀名(resourcePrefix)来避免,需要在组件的gradle脚本中配置:
andorid{
...
buildTypes{
...
}
resourcePrefix "moudle_prefix"
}
一旦配置resourcePrefix,所有的资源必须以该前缀名开头.比方上面配置了前缀名为moudle_prefix,那么所有的资源名都要加上该前缀,如:mouble_prefix_btn_save.
最后需要注意在Debug模式下和Release模式下,所需要的Context是不是你所但愿的,以免产生强转异常.
最先接触组件化这个概念是在从事广告SDK工做中,近期陆续续的作了一些总结,所以有了这篇关于”组件化开发”的文章.另外,组件化开发不是银弹,并不能全然解决当前业务复杂的状况,在进行项目实施和改进以前,必定要多加考量.
敬请期待第二篇,咱们将在第二篇内介绍怎样对项目实施组件化.