前言
之前学习组件化-路由的时候也是花费了不少的时间,其实学习技术都是这样,自己弄懂了大部分东西之后就会觉得这个知识好像并不是那么难。
这里的 “ 组件化-路由技术 ” 分成两篇文章讲解,确实内容略多一点,第一篇主要就是讲解组件化,而第二篇就主要讲解路由知识,这里是第二篇文章的链接。
我尽力讲得更加仔细一点,希望刚接触这项技术的小伙伴能够看得懂。
组件化的作用
组件化技术主要是进行项目比较大的团队才会采用的,想必它的作用很多小伙伴是清楚的了,我就简单提几点就行了。
- 提高编译速度: 该技术可以实现单独一个组件作为一个Application进行编译运行,例如我只想测试一下“登录、注册”组件,而我不必编译、运行整个项目,这样就可以提高我的开发效率。
- 解耦程度大: 解耦程度大不多解释,因为毕竟一个组件都可以单独运行了,你想它的解耦程度大不大呢?特别是将common(公共层)抽出来之后,用起来是真的舒服~
- 利于团队开发:这一点上感触颇深,在任务分配完成之后,就是感觉跟其它人的代码就完全分割开来了,写代码的过程很舒服,而且在git管理代码的过程中失误率也会小很多。
组件化实现
组件化实现比较轻松,下面我会将完整步骤都描述出来。
1. 统一每个组件的配置文件
第一步就是新建几个组件,选中项目new module就可以了,结果如下图所示:
在这里,我的想法是app作为应用壳组件,它负责APK的打包,管理其它组件,而没有业务逻辑;lib_common是公共层组件,是放置共用的网络请求、工具类的地方;而lib_home、lib_chat组件就是我们的业务逻辑组件。
如上图所示,每一个组件都有自己的build.gradle文件,我们肯定需要配置文件(.gradle)里信息的统一,防止私自修改gradle文件而影响整个项目的编译运行。我们需要创建一个config.gradle(上图所示)来统一gradle文件,config.gadle文件包含以下信息:
这一个config.gradle文件需要导入到项目配置文件中去,我们需要在project的build.gradle文件下代码的顶部加上apply from: "config.gradle"
来将我们的配置文件导入项目。接下来只需要在每个组件的build.gradle文件中这么使用:
2. 设置组件单独运行时的AndroidManifests.xml文件
在讲之前,我们先做一件事,由于common组件作为共用层,它肯定不需要单独运行,所以我们先将它导入其它的组件,按照添加三方库的办法,在其它组件的build.gradle文件中添加代码implementation project(':lib_common')
,以此导入本地库,然后,将app组件下的res文件全部导入common组件中去(layout目录就不用了,它就是app组件私有的),由于已经依赖了common组件,那么app中res的所有文件就可以删除了,不然就多了,而且重名。
我们可以打开某一个组件下的AndroidManifests.xml看一下,它没有<application></application>
标签,因为它此时是作为一个库来使用的,它不能够使用应用标签。同理,它也不能配置该标签下的信息,例如应用名、主题之类的。按照三方库形式导入其它组件后,这个manifests文件上的信息会被合并到另外一个组件的manifests文件上去。
为了使得我们的组件可以单独运行,我们需要单独为它创建一个manifests文件,我们在Project方式查看项目的方式下,在该组件下建立一个包,就叫alone包吧~,然后在该包下创建AndroidManifests.xml文件,我的建议是直接将app组件下的AndroidManifests.xml文件直接拷贝过来,然后稍微修改下,像下面这样:
这里大概能够理解为什么需要将res文件全部移动到common组件中去了吧,不然的app组件和chat组件是没有相互依赖的,chat组件就不能够使用图片、文字等资源了。
3. 实现两种运行模式
我们需要使项目有两种模式,一种是集成模式,一种是单独运行模式。
首先,我们在project下的gradle.properties文件中添加代码isRunAlone=true
,这个文件中可以放置项目需要使用的常量值,这句代码的意思就是定义了一个Boolean类型变量为true,就是“可单独运行”吧。
接下来在其它组件的build.gradle文件下,将顶部apply plugin: 'com.android.library'
代码修改为
if(isRunAlone.toBoolean()) {
apply plugin: 'com.android.application'
}else{
apply plugin: 'com.android.library'
}
这段代码的意思就是,通过常量值判断以哪种形式运行代码,.library
就是作为第三方库使用,不可单独运行,.application
就是可以作为一个应用单独运行。
我们要求在单独运行的模式下,能够使用我们自定义的manifests文件。以此需要在buildTypes
内添加以下代码:
sourceSets {
main {
if (isRunAlone.toBoolean()) {
manifest.srcFile 'src/main/alone/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
java {
//清除alone目录下的文件
exclude 'run_alone/**'
}
}
}
}
最后贴出home组件的完整build.gradle文件代码:
if (isRunAlone.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode rootProject.ext.android.versionCode
versionName rootProject.ext.android.versionName
testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
sourceSets {
main {
if (isRunAlone.toBoolean()) {
manifest.srcFile 'src/main/alone/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
java {
//清除run_alone目录下的文件
exclude 'run_alone/**'
}
}
}
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation rootProject.ext.dependencies.appcompat
implementation rootProject.ext.dependencies.constraint_layout
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation rootProject.ext.dependencies.junit
androidTestImplementation rootProject.ext.dependencies.runner
androidTestImplementation rootProject.ext.dependencies.espresso_core
//导入共用层组件
implementation project(':lib_common')
}
我们可以单独运行了吗?不可以,因为我们还没有启动活动
我们在每一个组建下创建一个活动,并在alone目录下的manifests文件中将它设置为启动活动。接下来就可以单独运行了。
注意事项
1. 资源名冲突
当我们切换成集成运行模式下的时候,两个组件中资源命名相同的话,就会导致资源名冲突,系统怎么会知道你想采用哪一个xml文件呢?
解决这个冲突也很简单,每一个组件都加上一个前缀就行了。添加代码resourcePrefix "前缀_"
在该组件的build.gradle文件中的buildTypes内就行了,在你创建xml文件的时候,系统就会强制要求你给该xml文件添加前缀,否则就会编译报错。记住,不是编译器自动添加前缀,而是手动添加前缀,不添加则编译报错。
2. 导库问题
通过implementation
形式导入的库具有相互依赖性,举个栗子,我们在app组件下导入home、chat的组件后,在chat组件中就可以使用home组件的文件,同理在home组件中就可以使用chat组件的文件。
但是,这个方法在导入第三方库的时候就行不通了。 在某个组件中使用implementation
导入第三方库,那么就只有该组件能够使用该第三方库。那么我们就应该使用api
的方式来实现第三方库导入,例如在common层gradle中加上代码api 'com.github.bumptech.glide:glide:3.7.0'
导入Glide库,可以实现在其它组件中也调用Glide第三方库。
仅仅在app组件下导入一次即可,单独将其导入其它业务组件代码贴出来:
if (!isRunAlone.toBoolean()) {
api project(":lib_chat")
api project(":lib_home")
}
3. manifests注册、权限问题
除了app、common组件,其它业务逻辑组件我们都应该具有两张表。但是每一次我们生成一个活动的时候,编译器只会在一张表上面去注册活动,因此一定要记住,我们需要手动在另外一张表上面注册活动。还有就是权限问题,一般我们只需要在common层的manifests文件中将所有权限都申明就可以了,不然的话,你还需要在业务组件上去申明两次权限(两张表)。
4. 签名配置
由于需要第三方平台的使用,需要我们提供应用的签名,我们要统一我们APK的签名。这里说一种最常用的自动签名的方式。在我们手动打包一次APK之后,生成了.key文件,接下来直接代码啦:
//在build.gradle的android 内
signingConfigs {
//签名配置要在buildtypes之前
//签名文件放在build.gradle同级目录
config {
//填写自己的key文件的相对路径
storeFile file("./key.jks")
storePassword "123456"
keyAlias "123456"
keyPassword "123456"
}
}
buildTypes {
release {
//使用签名
signingConfig signingConfigs.config
//混淆
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.config
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
我们需要在其它的组件下也添加这段代码,当然有快捷方式,就是在Android Studio的Project Structure中的signing去设置,它会自动在build.gradle中生成相应代码。组件化的介绍暂时就到这儿了,肯定是有许多地方是没有讲到的,就靠自己慢慢摸索啦~
下一篇文章讲路由,Android 讲解组件化-路由框架(2)
笔者水平有限,有写得不好的地方,请大胆指出~
转载请注明出处~