在AndroidSDK一文中,我们谈到了模块化和组件化。下面我们就来说说组件化发展的背后是什么。最早应用于广告SDK组件化,也适用于普通应用开发。下面的高能请大家做好心理准备,有不懂的可以私信交流。本文不建议初学者阅读。如果您是Android开发新手,请立即放弃阅读本文。模块化和组件化。模块化和组件化并不是新鲜的概念,一直被各行各业所重视。至于软件工程领域是什么时候提出组件化的,无从考证,但可以确定的是,组件化最先应用于服务端开发,后来在这种思想的指导下,出现了前端开发和移动端端开发也有自己的开发方式。在理解组件化之前,我们先回顾一下模块化的定义。模块化编程是一种软件设计技术,它强调将程序的功能分成独立的、可互换的模块,这样每个模块都包含仅执行所需功能的一个方面所需的一切。简单来说,模块化就是把一个程序按照功能进行拆分,分成独立的模块,使每个模块只包含与其功能相关的内容。我们对模块比较熟悉。比如登录功能可以是一个模块,搜索功能可以是一个模块,汽车的发射器也可以是一个模块。组件化现在我们来看“组件开发”,这里我们看一下它的定义:Component-basedsoftwareengineering(CBSE),也称为基于组件的开发(CBD),是软件工程的一个分支,强调关注点分离尊重整个给定软件系统中可用的广泛功能。它是一种基于重用的方法,用于定义、实现松散耦合的独立组件并将其组合到系统中。这种做法旨在为软件本身和赞助软件的组织带来同样广泛的短期和长期利益。通俗点说:组件化是基于可重用性的目的,将一个庞大的软件系统以关注点分离的形式拆分成多个独立的组件,耦合度较低。乍一看还是很抽象的。说了这么多,还是不懂。什么是组件?组件可以是模块、Web资源或软件包。比如汽车的发动机就是一个模块和一个组件,或者说是前端的一个组件。日历控件是一个模块,也是一个组件。模块化与组件化。看到这里,你心里一定有一丝寒意:模块化?组件化?这到底是什么?有什么不同?是的,模块化和组件化的本质是一样的,都是“大而小”。模块化的粒度更小,更注重复用,而组件化的粒度比模块稍大,更注重业务解耦。组件化的优缺点组件化开发的好处是显而易见的:系统级的控制细化到组件级的控制强度,复杂系统的构建最终是组件集成的结果。每个组件都有自己独立的版本,可以独立编译、测试、打包和部署。对于销售,用户可以选择使用哪些组件,组件可以灵活构建。配置管理、开发、测试、打包、发布完全控制在构建层面,带来诸多好处。比如升级一个组件的小版本,如果对外提供的接口没有变化,其他组件根本不需要测试。但是组件化的实现对开发人员和团队管理者提出了更高的要求。与传统方式相比,项目的管理和组织难度更大,需要开发人员对业务有更深入的了解。进入Android项目为什么要在Android中实现组件开发?根本原因是业务的增长增加了项目的复杂度。为了更好的适应团队开发,提高开发效率,实现组件化是大势所趋。为了更好的帮助大家理解上面这句话,我先从最早的Android项目开发方法说起。简单开发模式所谓简单开发模式是最基本的开发方式。项目中没有所谓的模块,也没有所谓的规划。经常在初学者写的demo或者个人学习过程中看到。它的结构大致如下:不难发现,它经常出现在一个界面中。业务逻辑量很大,业务逻辑中充斥着各种网络请求、数据操作等行为。整个项目没有所谓的模块概念。项目的基本单元不是模块,而是方法层级。关于这种开发模式,没什么好介绍的。早期我们也体验过,现在除了非常老的项目和初学者动手的情况下很少见了。单项目开发模式这种开发模式已经有了清晰的模块划分,逻辑上分层呈现出更好的结构。这个模型是我们最熟悉的。通常用于早期产品的快速开发,团队规模较小。这种开发模式的结构如下:随着产品的迭代,业务变得越来越复杂,随之带来的是项目结构复杂度的极度增加。这时候我们面临几个问题:实际业务变化非常快,但是项目之前的业务模块耦合度太高,牵一发而动全身。是项目所做的任何修改,每次都要编译整个项目的功能测试和系统测试。团队协同发展的矛盾较多。需要花更多的时间在沟通协调上,在开发过程中,没有一个成员可以专注于自己的功能点,影响开发效率。他们不能灵活地配置和组装项目。比如今天产品经理说加这个功能,明天说去掉,后天加。面对这些问题的前提下,让我们重新思考组件化,看看它能不能解决我们在Android项目开发中遇到的问题。主项目的多组件开发模型采用了组件化的思想,我们在“单项目”模型的基础上,将业务层的业务抽取出来,打包成相应的业务组件,以及将基础库的部分提取出来打包成基础组件,主工程是一个可运行的app,作为各个组件的入口(主工程也叫shell程序)。这些组件以jar或aar的形式呈现。主工程以依赖的方式使用组件提供的功能。(需要注意的是,这是理想的结构图,在实际项目中,业务组件之间会有通信,也会有依赖关系,这个我们下面会讲到)不管是jar还是aar,都是库中的本质上,它们不能独立于主项目运行。.团队成员参与项目开发时,每个成员的开发设备至少要有主项目和自己的组件。不难看出,通过项目的组件化,每个成员都可以专注于自己负责的业务,不影响其他业务,同时借助稳定的基础组件,可以大大减少代码缺陷减少,使整个团队能够以并行开发的方式高效推进开发进度。不仅如此,组件化让我们可以灵活的组装产品,我们要做的就是根据需要配置相应的组件,最终生产出我们想要的产品。这有点像玩积木。通过不同地放置它们,我们可以获得我们想要的形状。对于测试同学来说,可以有效减少测试的时间:原有业务不需要再次进行功能测试,可以专注于变更业务的测试和最终的集成测试。至此,我们已经有效解决了“单一项目开发模式”的一些问题对于大多数团队来说,这已经足够了,但是这个模型还有一些可以改进的地方:每次修改依赖包,都需要重新编译生成lib或者aar。比如小燕接手的一个项目,有40多个组件。在整合所有组件时,小燕发现其中一个组件存在问题。为了定位和修改组件中的问题,小燕继续调试组件。因为在这种模式下,组件无法脱离主工程,这意味着小燕每次修改后都要等待漫长的编译过程。更糟糕的是,距离上线只有5个小时,每次编译需要10分钟。为了修复这个bug,编译了20次,嗯……什么都不用做,提交辞职报告就可以了。如何解决每次修改组件都要和主工程一起编译的问题?我们来看看主项目的多子项目开发模型是怎样的。解决这个问题。主项目多子项目开发模式这种开发模式是在“主项目多组件”开发模式的基础上改进而来的,其结构图如下:不难发现,这种开发模式是结构上类似于“主项目多组件没有区别,唯一的区别是所有业务组件不再是moubles而是作为子项目,基础组件可以是moudle,也可以是子项目,其中与主工程不同的是:Debug模式作为一个app,可以独立开发、运行、调试;在Release模式下,作为一个Library,被主工程依赖,为主工程提供服务。model,当小燕发现某个业务组件存在缺陷时,会怎么处理呢?比如基础组件2有问题,由于基础组件2在Debug模式下可以作为app独立运行,所以很容易修改调试单独g模块。最后修改完成后,只需要重启一次就可以编译整个工程了。不难发现,这种开发模式有效的减少了全量编译的次数,缩短了编译时间,方便了开发者的开发调试。对于测试同学来说,功能测试可以提前做好,并且可以及时参与到开发过程中,将风险降到最低。到现在为止,我们已经在理论层面解释了采用组件化开发给我们带来的便利,空话是没有说服力的。下一节我们就来说说Android中如何实现组件化。组件化过程中遇到的问题。组件划分组件化首先要做的就是划分组件。如何划分并没有一个确切的标准。我建议尽早实现组件优化时,可以在“粗”粒度上进行。这样做的好处是后期可以随着对业务的了解再细分,不需要太大的成本。当然,我建议划分组件。一件作品由团队架构师和业务人员定制。子项目工作模式切换在“主项目的多子项目模型”中,我们提到子项目在Debug模式下作为一个单独的Application运行,在Release模式下作为一个Library运行,如何动态修改子项目的运作模式?我们都知道,在用Gradle构建的项目中,使用applyplugin:'com.android.application'来标识Application,applyplugin:'com.android.library'flagLibrary。因此,我们可以在编译时通过判断构建环境中的参数来修改子项目的工作模式,在子项目的gradle脚本头部添加如下脚本片段:另外,在子项目不同的运行模式下,它的AndroidMainifest.xml也不一样,需要提供自己的AndroidManifest.xml文件:在子项目src目录下创建两个目录(在其他位置创建)存放不同的AndroidManifest。以xml为例,这里我创建了debug和release目录,然后在子项目的gradlebuild脚本中也需要按照构建方式制定:组件通信和组件依赖。在“主项目多组件”的理想模型下,业务组件是不存在相互通信和依赖的,但现实情况恰恰相反,如下图所示:这里,业务组件1和业务组件3提供服务??给同时依赖业务组件2,即业务组件2需要同时依赖业务组件3和业务组件1。现在我们来看一个更糟糕的情况:从这个角度来看,在业务复杂的情况下,组件之间的相互依赖会带来两个问题:重复依赖:比如可能有业务组件3依赖业务组件1,而业务组件2依赖业务组件3和业务组件1,此时重复依赖业务组件1。子系统通信方法不能依赖传统的显示意图。在这种模型下,使用displayintent会导致组件高度耦合。例如,业务组件2依赖于业务组件1,并通过显示意图进行通信。一旦业务组件1不再使用,业务组件2使用现实意图的地方就会出现错误,这显然与我们的组件化有关。目的背道而驰。解决组件通信首先要解决业务组件通信的问题。当我们看到上面复杂的组件通信图时,我们不难想到操作系统引入了总线机制来解决设备挂载问题。同样,我们借用总线的概念。将“组件总线”添加到项目中不同组件之间的通信结构如下:挂载在组件总线上的所有业务组件都可以实现双向通信。通信协议类似于HTTP通信协议,即基于URL。至于实现方式,一是可以根据系统提供的隐含意图,二是完全自己实现组件总线。本文在此不做赘述。解决重复依赖。对于使用aar输出的库,在构建项目时,gradle会为我们保留最新版本的aar。也就是说,如果依赖以aar的形式提供给主工程,就不会出现重复依赖的问题。如果直接以项目的形式提供依赖,会在打包过程中出现重复代码。目前解决项目重复依赖的方法有两种:1、对于纯代码项目的库或jar包,只在最终项目中执行compile,其他情况使用provider方式;2.编译时检测依赖包,已经依赖不再依赖资源id冲突将多个组件合并到主工程时,可能会出现资源引用冲突。最简单的方法就是避免使用资源前缀名(resourcePrefix),需要在组件的gradle脚本中的Configuration中:一旦配置了resourcePrefix,所有资源都必须以该前缀开头。比如上面配置的前缀为moudle_prefix,那么所有的资源名称都要加上前缀,比如:mouble_prefix_btn_save。组件上下文(Context)最后需要注意在Debug模式和Release模式下需要的Context是否是你想要的,避免强制异常。结束语最早接触组件化概念是在做广告SDK的工作中,最近一直在继续做一些总结,所以就有了这篇关于“组件化开发”的文章。另外,组件化开发也不是灵丹妙药,不能彻底解决当前复杂的业务情况。在项目实施和改进之前,必须多加考虑。敬请期待第二篇,我们将在第二篇介绍如何为项目实现组件化。
