1为什么采用组件化开发
理由很简单, 提高团队开发速度.特别是业务模块繁琐的项目,主要体现在一下几点
- 解耦
- 每个功能模块都可单独运行, 开发期,只编译一个模块即可(这是组件独有的亮点)
- 有利于单元测试
- 代码迭代便捷
举个栗子
上图是常见的普通项目的架构,主工程依赖各业务模块, 各业务模块都依赖相同的支持库,例如日志库,工具类库等,当A业务改一行代码, 编译看效果时,要都编译,这样效率相当慢. 当然有人会选择单元测试,当然为了一行代码单独写个单元测试有点没必要,如果还设计其他模块可能会更复杂 如下图
上图单一工程模型下的业务关系,总的来说就是:你中有我,我中有你,相互依赖,无法分离。
然而随着产品的迭代,业务越来越复杂,随之带来的是项目结构复杂度的极度增加,此时我们会面临如下几个问题:
1、实际业务变化非常快,但是单一工程的业务模块耦合度太高,牵一发而动全身;
2、对工程所做的任何修改都必须要编译整个工程;
3、功能测试和系统测试每次都要进行;
4、团队协同开发存在较多的冲突.不得不花费更多的时间去沟通和协调,并且在开发过程中,任何一位成员没办法专注于自己的功能点,影响开发效率;
5、不能灵活的对业务模块进行配置和组装;
为了满足各个业务模块的迭代而彼此不受影响,更好的解决上面这种让人头疼的依赖关系,就需要整改App的架构。
2 组件化的介绍
业务组件之间是相互独立的,但是又都被APP壳工程依赖,这样app壳工程可以调用组件,当时有个问题,组件之间怎么通信呢??? 这个问题就要交给路由协议了,(例如: ActivityRouter, ARouter)
很详细我就不介绍了 文末参考文章都写的很详细,直接撸代码
开始实践
1)组件模式和集成模式的转换
- 首先介绍项目 今天我们新建一个app 壳工程 和 两个逻辑模块 main(即主工程,但是他只负责用户登录等相关操作) 和keepAlive(保活工程) , app壳文件依赖这两个组件工程, 如下图
2.在项目的根目录中生成一个文件 gradle.properties加入 一个变量isModule
# 每次更改“isModule”的值后,需要点击 "Sync Project" 按钮
# true 是组件模块,说明是单独的App
# false 是集成模式,说明是依赖Lib
isModule=false
- 在逻辑模块的 build.gradle 中加入如下配置
if (isModule.toBoolean()) {
apply plugin: com.android.application
} else {
apply plugin: com.android.library
}
- 同步下项目 此时项目还没有任何变化
- 把isModule 的值改成 true 然后同步项目,这时候项目就傻眼了,壳项目找不库, 两个组件虽然变成了独立的应用,但是不能直接运行,会报错,
- 解决壳文件出错, 在文件的依赖里添加如下判断代码, 然后同步, 此时壳文件没有问题了
if (isModule.toBoolean()) {
// 可以写一下基类库
} else {
implementation project(path: ':module_main')
implementation project(path: ':module_keepAlive')
}
- 两个组件不能运行 因为表单文件不完整, 为了后期合并时不影响整体项目,所以 在main下创建一个module文件夹,并创建 AndroidManifest.xml 可以按照壳文件 添加完整 主要是application 标签, package 名就不要改了
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.zhf.keepalive">
<application
android:name=".debug.App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
</application>
</manifest>
8. 在组件的build.gradle 文件的 android 标签里填加如下判断代码
sourceSets {
main {
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/module/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
//集成开发模式下排除debug文件夹中的所有Java文件
java {
exclude 'debug/**'
}
}
}
}
- 非完美CV工程师会发现 在集成模式时 有这么一个配置 exclude ‘debug/**’,
- 在 项目包名下创建 debug文件夹 主意这里面的文件只有在组件模式下才会运行,配置在第8步中已经添加
- 在debug文件夹下创建一个activity , 记得在module目录下的配置文件注册并设置为入口页面,如下
<activity android:name=".debug.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
其实到了这里你的两个功能模块就可以单独运行了,如果到这里没有问题那就在模块工程里(非debug文件下 )创建一些页面吧
我项目中 splashActivty 只有是组件模式时才会调用, keepMainActiviyty 则什么模式下都可以调用,
2) 模块路由配置
上图中我们说了 keepMainActiviyty 什么模式下都能调用, 我们知道在集成模式下 很简单,写个intent 就可以开启了,但是在集成模式下(合并成一个完整项目)怎么办呢,这事就要引入 路由框架了 这里以 ARouter为例
- 现在我们再创建一个库 lib_common 所有组件都依赖他,是所有组件基础库
- 只在lib_common库 中引入下面依赖
api 'com.alibaba:arouter-api:1.5.0'
- 在app壳 .main库 和keepAlive库 中引入下面依赖
annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'
implementation project(path: ':lib_common')
- 在所有组件build.gradle在android 标签里添加如下
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
- 配置完成 接下来就开始使用, 我有个需求 想跨组件跳转到module_keepAlive 组件中的 keepMainActivity 页面 要在这个activity上面加上 @Route 注释 其中path 的值 必须是两级目录, 也就是要有两个 反斜杠 这是 " 亀腚 "
@Route(path = "/keepalive/KeepMainActivity")
public class KeepMainActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
- 在要跳转的地方直接调用如下代码就可以了 , 加try catch 是怕蹦沙卡拉卡
try {
ARouter.getInstance().build("/keepalive/KeepMainActivity").navigation();
} catch (Exception e) {
e.printStackTrace();
}
别忘了在项目的两个AndroidManifest.xml 表单文件中都注册 上activity ,debug 文件夹下的除外,这样合成完成项目时, 表单文件也会合并,最好不要出现重名和资源冲突问题.
别忘了把 isModule 的值改成 false 并同步项目, 到此基本完成了组件化项目
3 全局的 application 说明
- 在lib_commom 创建一个 BaseApp 继承application
- 在 app壳 module_main 和module_keepAlive 中继承 BaseApp, 注意两个module的 BaseApp的实现直接放在debug下,
- 别忘了表单文件中注册 application ,同样的注意两个module的只在module文件下的表单文件中注册就可以了.