Android组件化学习笔记
学习过程产生的示例代码已开源
组件化意义
- 解耦,增加可维护性
- 提高代码利用率
- 多人开发时防止代码胡乱修改
- 组件即可同时编译打包,又可以作为App单独编译打包,提高调试效率
实现记录
模块
项目应分解为多个模块,其中包含以下内容
- 项目的App外壳
- 各个组件的代码
- 各个组件公用的代码单独组成模块
例如在实例代码中,我的项目模块如下
- app:项目外壳
- commonLib:公共代码,如基类、工具类
- module0:模块0
- module1:模块1
- module2:模块2
模块配置
公共配置
使用根目录的gradle.properties
进行全局配置。我将判断子模块是否作为独立app进行编译的变量放在这里
# gradle.properties
...
# Module0 是否以App编译
isModule0AsApp=false
# Module1 是否以App编译
isModule1AsApp=false
# Module2 是否以App编译
isModule2AsApp=false
在Gradle中用isModule0AsApp.toBoolean()
获取这些变量为每一个组件进行配置。以Module0为例
// module0/build.gradle
//判断当前模块是否应以App进行编译
if (isModule0AsApp.toBoolean())
apply plugin: 'com.android.application'
else
apply plugin: 'com.android.library'
...
android {
...
defaultConfig {
//若以app进行编译,则应为其赋予独立的应用包名
if (isModule0AsApp.toBoolean())
applicationId "com.binzee.modularzationtest_java_module0"
...
}
...
sourceSets {
//当组件以app编译或以模块进行编译时,其使用的manifest应该是不同的。
//我在模块内的main文件夹下新建了"asApp""asLibrary"两个文件夹
//并将原模块manifest放入"asApp"中
main {
if (isModule0AsApp.toBoolean())
manifest.srcFile 'src/main/asApp/AndroidManifest.xml'
else
manifest.srcFile 'src/main/asLibrary/AndroidManifest.xml'
}
}
}
每个模块应该有作为app、作为模块时使用的不同的AndroidManifest。在sourceSets中进行配置
依赖
项目往往会依赖各种库,我的做法是让commonLib模块依赖这些库,然后其它所有的模块依赖commonLib模块。在Gradle中用api
替代implementation
导入这些依赖
// app/build.gradle
...
dependencies {
api libraries.appcompat
api libraries.surpportDesign
api libraries.constraintLayout
//aRouter
implementation libraries.arouter
annotationProcessor libraries.arouterCompiler
testImplementation 'junit:junit:4.13.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
一些各模块公用的Gradle配置,可以在项目根目录下新建config.gradle
,并在其中进行配置
// config.gradle
ext {
android = [
compileSdkVersion: 30,
buildToolsVersion: "30.0.2",
minSdkVersion: 23,
targetSdkVersion: 30,
]
dependencies = [
appcompat: 'androidx.appcompat:appcompat:1.2.0',
surpportDesign: 'com.google.android.material:material:1.2.1',
constraintLayout: 'androidx.constraintlayout:constraintlayout:2.0.2',
arouter: 'com.alibaba:arouter-api:1.5.1',
arouterCompiler: 'com.alibaba:arouter-compiler:1.5.1'
]
}
然后将其导入项目build.gradle中
// project/build.gradle
apply from: "config.gradle"
...
接下来即可在各个gradle中通过rootProject.ext.android
和rootProject.ext.dependencies
获取。
模块分别编译
有时候某模块的一个小改动不需要重新编译整个项目。此时组件化的最大优势便体现出来了。将之前在gradle.properties
中相应模块的配置置为true,即可在Android Studio顶部工具类左侧的module框中找到该模块,选中其并进行编译即可打包出相应的app(记得在该模块的app Manifest中设置启动Activity)
组件间跳转
该示例代码使用的是ARouter进行跳转。可以自行查阅相关信息
ARouter 小提示
- 记得在每一个模块中依赖ArouterApi,以及其Compiler(详见官方Readme)
- 记得在项目最初用
ARouter.init(Context ctx)
进行路由注册 - 记得在每一个节点中调用
ARouter.getInstance().inject(Object thiz)
将节点注入,并在节点的class声明前通过注解@Route(path = "/xx/xxx")
进行注册 - 注解
@Route(path = "/xx/xxx")
的路径必须至少为二级 - 建议学习
IInterceptor
拦截器的使用,利用其可以实现模块跳转拦截,和登陆状态验证