随着App的不断迭代,业务会变得愈来愈复杂,业务模块会愈来愈多,且每一个模块的代码也会变得愈来愈多。为了应对这一场景,咱们须要把不一样的业务模块划分红一个个组件,在修改业务代码的时候只须要在对应模块修改就能够了。经过高内聚,低耦合的业务模块来保证工程的健壮性和稳定性。如今问题来了,当组件的数量变得越来多的时候,咱们如何管理业务组件呢?java
原创声明: 该文章为原创文章,未经博主赞成严禁转载。
<!--more-->
先来看看Android组件化须要实现的目标。(什么是组件化构建?)android
对于第一点:须要根据技术架构和业务架构来划分模块,这里须要根据实际状况来考虑。咱们须要优化的是第2、3、四点。git
对于第二点:Android是经过应用com.android.application或com.android.library来决定该模块是以App模式仍是以Library模式构建。App模式和Library模式的最大区别就是,App可以启动,而Library不能够。因此若是咱们的模块能独立启动的话,咱们须要每次手动去改动模块的build.gradle文件。好一点的作法定义一个布尔值来判断是否处于debug模式,可是这里有个问题是,不是每一个模块都能独立启动的。因此不管采用何种方案,都须要咱们手动管理。github
对于第三点:当咱们开发好业务模块后,可能咱们须要频繁的新增或删除某些业务模块。若是是这样的话,咱们也是须要频繁手动修改App的build.gradle。数据库
对于第四点:有时候,咱们可能会在不一样的App中引用相同的组件(例如:滴滴的普通版和企业版,普通版包含企业版的功能),这个时候,咱们也不但愿要频繁手动管理组件依赖,特别是在组件还能够独立运行的时候。架构
因此,在咱们实践组件化的时候,最大的问题就是,咱们须要频繁的手动build.gradle文件来管理组件应用的插件和App的依赖。app
先安利下笔者写的Gradle插件:Calces。若是以为这个插件有用的话,能够star下,若是你有更好的想法的话,能够向我提交pull request。框架
废话少说,如下是经过Calces快速实现Android组件化构建的流程。maven
你的支持,是我前进的动力,若是以为有帮助的话,能够点下star👍
Demo地址:SimpleCalces组件化
项目结构:
在Gradle 2.1及更高版本的插件构建脚本代码:
在项目的build.gradle中
buildscript { ... } plugins { id "calces.modules" version "1.0.11" }
在较旧版本的Gradle中或须要动态配置的状况下的插件构建脚本代码:
buildscript { repositories { maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath "gradle.plugin.com.tangpj.tools:calces:1.0.11" } } apply plugin: "calces.appConfig"
appConfig { debugEnable false apps { app{ modules ':library1', ':library2' } } modules{ library1{ mainActivity ".Library1Activity" applicationId "com.tangpj.library1" isRunAlone true } library2{ mainActivity ".Library2Activity" applicationId "com.tangpj.library2" isRunAlone true } } }
apply plugin: 'calces.modules'
这样咱们就完成了组件化的构建了,是的,咱们再也不须要再手动管理单个组件了与App的构建了,经过Calces,咱们能实现快速的组件化构建与多App同时构建。
那么问题来了,咱们如何实现组件间的通讯呢?在简单的项目中,推荐该Demo同样,经过使用Android隐式Intent来实现组件间通讯。在中大型项目中,笔者推荐使用阿里的路由解决方案:ARouter。具体使用方法参考官方文档就能够了,使用方法十分简单。
注意:在使用隐式Intent实现组件件通讯的时候须要注意找不到相应组件异常:java.lang.IllegalStateException: Could not execute method of the activity。致使这个异常的缘由是找不到目标组件致使的,因此在实际开发的时候,须要捕获这一异常,而且根据项目实际状况来进行实际的处理。使用ARouter框架则能经过设置降级策略来实现异常处理(查看ARouter文档了解更多)。
若是只是实现项目的简单组件化,那么看到这里就能够了,若是但愿实现更加灵活的组件化架构的读者能够继续看下去,下面笔者将全面分析组件化的优点与笔者总结的组件化构建思想。
组件化构建与其说是一种技术,不如说是一种思想。组件化构建是经过对项目从新划分红一个个高内聚、低耦合的模块来解决项目过于臃肿,代码过于复杂的一种架构思想。
咱们经过对Google官方的架构演示Demo todo-mvp进行拆分来对Android组件化进行深刻的分析。
Demo地址:TodoCalces
todo系列app是Google android-architecture项目中为了演示Android架构的最佳实现而编写的一系列演示Demo。todo app的特色是,它足够简单,代码量少,易于理解。可是又不会过于简单,由于它是一个包含完成功能的App。它实现了任务列表、任务详情、新建任务、编辑任务、统计任务的功能。
todo-mvp实现的功能:
咱们将以todo-mvp的功能来划分为4个业务模块,将底层划分为2个模块,分别是superLib(提供mvp架构支持与其它的一些支持库功能)与dataLib(数据支持模块,Room提供底层数据库支持功能)。对于大型项目还能够加入resLib支持模块,用来存放公共图片资源、字符穿资源、样式等。
架构划分图以下:
从架构图能够看出,全部的业务组件都依赖底层库,而APP又依赖于业务组件,APP组件在这里是做为一个独立组件存在的。在通常的组件化实践中,都不包含APP这个组件的,APP组件的存在是有其意义的。
首先,咱们的组件化除了实现组件的独立管理和动态配置APP所依赖的组件外,还有一个十分重要的目的就是,经过组合不一样的组件,打包多个不一样的APP。例如,QQ有分普通版和轻聊版,轻聊版是功能简化版的QQ。若是咱们使用组件化来管理工程的话,咱们只须要把不须要的模块移除掉就能够了。而APP组件在这里的做用是充当一个包装盒,把须要的组件包装进来。而且咱们能够经过控制包装盒的样式来配置不一样的APP风格。在这里咱们能够经过Application中的Style来实现。
这里咱们仍是以todo-mvp为例,例如咱们须要实现一个不包含统计功能的todo APP,按照咱们的原理,咱们只须要去掉statistics的依赖就能够了。
架构划分图以下:
若是nostatsitcs须要不一样的配色的方案的话,只须要在AndroidManifest的application标签中配置对应的theme就能够了。
经过上面的分析,咱们来试下对todo-mvp项目按照业务功能来划分组件。咱们先来看看划分后的目录:
好了,咱们已经对todo-mvp项目进行初步的划分了。根据上面分析的理论得知,咱们的业务模块是能够单独运行的,而且咱们可以快速构建一个不包含statistics模块的APP。
咱们只须要使用Calces就能快速实现咱们须要的功能。
按照Calces的教程,咱们得知,实现Calces只须要三个步骤:
第一点和第三点在其它全部项目中的配置都是同样的,在这里不做论述,下面咱们看看对于TodoCalces项目,咱们要如何配置AppConfig 。
appConfig { debugEnable false apps { app { mainActivity "com.tangpj.tasks.TasksActivity" modules ':modules:addtask', ':modules:taskdetail', ':modules:tasks', ':modules:statistics' } app2 { name 'nostatistic' applicationId 'com.tangpj.nostatistic' modules ':modules:addtask', ':modules:taskdetail', ':modules:tasks' } } modules { addtask { name ":modules:addtask" applicationId "com.tangpj.addtask" mainActivity ".AddEditTaskActivity" isRunAlone false } taskdetail { name ":modules:taskdetail" applicationId "com.tangpj.taskdetail" mainActivity ".TaskDetailActivity" isRunAlone true } task { name ":modules:tasks" applicationId "com.tangpj.tasks" mainActivity ".TasksActivity" isRunAlone true } statistics { name ":modules:statistics" applicationId "com.tangpj.statistics" mainActivity ".StatisticsActivity" isRunAlone true } } }
根据AppConfig能够得出,咱们分别配置了2个APP,分别是app1和app2。而且app2中是没有依赖statistics的。如今咱们两个APP运行的对比图。
app1(带statistics模块):
app2(不带statistics模块):
从运行图能够看出,app1和app2的配色方案是不同的,而且app2中不带statistics模块,经过对项目实行合理的划分和引入Calces就可以快速实现组件化构建了。
结论:经过Calces能轻松实现业务组件的管理,多APP的快速构建。当咱们的业务组件只有4个的时候,可能没法体现Calces的优点,可是若是咱们的业务组件有40个的时候,Calces给咱们带来的优点就很是明显了。咱们能够经过灵活依赖不一样的组件,实现快速构建多个APP的目的。就像Calces的介绍图案同样,把组件当成积木来使用。
Android自动化测试展开来讲是一个很是大而且不算简单的工程,在这里笔者不打算展开来讲。只是简单的介绍组件化构建如何让咱们更方便地去测试。
并非全部的自动化测试都同样,它们一般在使用范围、实现难度和执行时间上存在不一样。咱们通常把自动化测试划分为三种分别是:
为了优化投资回报率,代码库应该包含大量的单元测试、少许集成测试以及更少的功能测试。
占好比下图所示:
从上文知道,在咱们的组件化分的时候,会划分一个基础依赖库(superLib)。基础依赖库为咱们的项目提供了基本的支持,而且该库在项目中是比较稳定、而且不包含业务逻辑的,因此在基础依赖库中,咱们应该大量应用单元测试。而集成测试则适用于咱们的数据依赖库(dataLib)中,咱们能够经过集成测试来验证产品代码与数据模块的交互。而咱们的业务模块中包含了大量的业务逻辑,这部分是常常变更的部分,咱们能够为咱们的业务模块编写一些UI自动化测试代码,可是由于业务(界面)常常变更的缘由,因此这部分测试代码是难以维护,而且复用性十分低的。。
最后,咱们得出的结论是:应该把主要精力放在单元测试上,因此若是当你的精力不足以编写全部测试代码的时候,你应该把主要的精力放在单元测试上,而不是放在收益最小的功能测试上。
关于自动化测试,笔者给的建议就到这里了,若是须要深刻理解测试的话,能够自行查找资料,或者关注笔者的博客。后续的博客中,有可能会写关于自动化测试相关的知识。
经过Calces插件,咱们在实现Android组件化时只须要关注如何合理划分组件的架构与如何实现组件间的通讯就能够了。对于Android组件化来讲,最主要问题有两个:
第二个问题,能够经过Calces快速解决,至于第一个问题,笔者给出的指导就是,业务模块在合理的状况下要尽量的小,由于越小的模块,越容易达到高内聚低耦合的目的。读者不须要担忧项目模块划分得过于细不便于管理的问题,由于Calces可以轻松帮你管理好各个模块。
Android开发利器之Data Binding Compiler V2 —— 搭建Android MVVM彻底体的基础
若是这片文章对你有所启发的话,能够关注下笔者的公众号或GitHub。
扫一扫关注我: