android 组件化重构项目
1.为什么要组件化
(1)耦合严重:单一工程的业务之间耦合度太高,牵一发而动全身
(2)编译时间慢: 对工程的任何更改都必须编译整个工程
(3)测试麻烦:功能测试和系统测试每次都要进行
(4)开发效率不高:共同开发时容易产生冲突
(5)不够灵活:不能灵活的对业务模块进行配置和组装;
2.组件化介绍
组件化就是一个完整的app拆分成多个子模块每个子模块可以独立的编译或者运行,可以任意组合成另一个新的app或者模块,每个模块之间几部想不依赖有可以相互交互 。
组件化的基本组成:
(1)app壳工程:就是一个空的工程,负责打包apk没有具体的业务功能
(2)业务组件:每个业务模块单独出来可以形成一个独立的工程
(3)common组件:为每个业务模块提供公共的组件 如 工具类 网络类的封装
(4)三方组件:把一系列的三方类的功能集合在一起形成的组件 如 微信支付+支付宝支付 +其他三方支付= 支付组件
3.组件化实施流程
由于是之前自己独立开发的一个比较小的工程,所有逻辑也是自己写的所以实施组件化起来还是比较方便的,因为是重构以前的工程而不是重写 所以需要一步步的进行 从开始学习开始 到最后的组件化完成 差不多一周时间 。
(1)拆解工程 提取commonLibrary模块
我们在提取过程中要做的事情
1.为了保证每个业务组件的版本的统一个模块是否模块化的开启
添加统一的引用的gradle config.gradle 在这里吧原来使用的引用和版本都添加进来
/**
* 全局统一配置文件
*/
ext {
//true 每个业务Module可以单独开发
//false 每个业务Module以lib的方式运行
//修改之后需要Sync方可生效
isModule = false
//版本号
versions = [
applicationId : "com.example.componentapplication", //应用ID
versionCode : 1, //版本号
versionName : "1.0.0", //版本名称
compileSdkVersion : 28,
buildToolsVersion : "28.0.3",
minSdkVersion : 17,
targetSdkVersion : 23,
androidSupportSdkVersion: "28.0.0",
constraintLayoutVersion : "1.1.1",
runnerVersion : "1.0.1",
espressoVersion : "3.0.1",
junitVersion : "4.12",
annotationsVersion : "24.0.0",
javaSDKVersion : 1.8,//javaSDK版本
multidexVersion : "1.0.2",
butterknifeVersion : "9.0.0",
arouterApiVersion : "1.4.0",
arouterCompilerVersion : "1.2.1",
arouterannotationVersion: "1.0.4",
gsonVersion :"2.4",
//rxjava 家族和网络请求
rxjavaVersion :"2.1.6",
rxandroidVersion :"2.0.1",
retrofitVersion :"2.3.0",
convertergsonVersion :"2.2.0",
rxjava2adapterVersion :"2.3.0",
logginginterceptorVersion:"3.7.0",
takephotolibraryVersion :"4.0.3" ,
glideVersion :"3.8.0",
baservadapterVersion :"3.0.3",
flowlayoutVersion :"1.0.3",
permissionVersion :"1.1.0",
autosizeVersion :"1.1.2"
]
dependencies = [
"appcompat_v7" : "com.android.support:appcompat-v7:${versions["androidSupportSdkVersion"]}",
"constraint_layout" : "com.android.support.constraint:constraint-layout:${versions["constraintLayoutVersion"]}",
"runner" : "com.android.support.test:runner:${versions["runnerVersion"]}",
"espresso_core" : "com.android.support.test.espresso:espresso-core:${versions["espressoVersion"]}",
"junit" : "junit:junit:${versions["junitVersion"]}",
"support_annotations" : "com.android.support:support-annotations:${versions["annotationsVersion"]}",
"design" : "com.android.support:design:${versions["androidSupportSdkVersion"]}",
"support-v4" : "com.android.support:support-v4:${versions["androidSupportSdkVersion"]}",
"cardview-v7" : "com.android.support:cardview-v7:${versions["androidSupportSdkVersion"]}",
"recyclerview-v7" : "com.android.support:recyclerview-v7:${versions["androidSupportSdkVersion"]}",
//方法数超过65535解决方法64K MultiDex分包方法
"multidex" : "com.android.support:multidex:${versions["multidexVersion"]}",
//路由
"arouter_api" : "com.alibaba:arouter-api:${versions["arouterApiVersion"]}",
"arouter_compiler" : "com.alibaba:arouter-compiler:${versions["arouterCompilerVersion"]}",
"arouter_annotation" : "com.alibaba:arouter-annotation:${versions["arouterannotationVersion"]}",
"butterknife_compiler": "com.jakewharton:butterknife-compiler:${versions["butterknifeVersion"]}",
"butterknife" : "com.jakewharton:butterknife:${versions["butterknifeVersion"]}",
"gson" : "com.google.code.gson:gson:${versions["gsonVersion"]}",
"rxjava" : "io.reactivex.rxjava2:rxjava:${versions["rxjavaVersion"]}",
"rxandroid" : "io.reactivex.rxjava2:rxandroid:${versions["rxandroidVersion"]}",
"retrofit" : "com.squareup.retrofit2:retrofit:${versions["retrofitVersion"]}",
"convertergson" : "com.squareup.retrofit2:converter-gson:${versions["convertergsonVersion"]}",
"rxjava2adapter" : "com.squareup.retrofit2:adapter-rxjava2:${versions["rxjava2adapterVersion"]}",
"logginginterceptor" : "com.squareup.okhttp3:logging-interceptor:${versions["logginginterceptorVersion"]}",
"glide" : "com.github.bumptech.glide:glide:${versions["glideVersion"]}",
"baservadapte" : "com.zhy:base-rvadapter:${versions["baservadapterVersion"]}",
"flowlayout" : "com.zhy:flowlayout-lib:${versions["flowlayoutVersion"]}",
"permission" : "com.yanzhenjie:permission:${versions["permissionVersion"]}",
]
}
然后一定要记得 在application 的 gadle中添加
apply from: "config.gradle"
否则会报 类似这种的错误
ERROR: Cannot get property 'versions' on extra properties extension as it does not exist
然后就是修改commonlibrary的gradle
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.versions.compileSdkVersion
buildToolsVersion rootProject.ext.versions.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.versions.minSdkVersion
targetSdkVersion rootProject.ext.versions.targetSdkVersion
versionCode rootProject.ext.versions.versionCode
versionName rootProject.ext.versions.versionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//Arouter路由配置
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
includeCompileClasspath = true
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
compileOptions {
targetCompatibility rootProject.ext.versions.javaSDKVersion
sourceCompatibility rootProject.ext.versions.javaSDKVersion
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
//把implementation 用api代替,它是对外部公开的, 所有其他的module就不需要添加该依赖
api rootProject.ext.dependencies["support_annotations"]
api rootProject.ext.dependencies["junit"]
//MultiDex分包方法
api rootProject.ext.dependencies["multidex"]
//Arouter路由
annotationProcessor rootProject.ext.dependencies["arouter_compiler"]
api rootProject.ext.dependencies["arouter_api"]
api rootProject.ext.dependencies["arouter_annotation"]
//解析
api rootProject.ext.dependencies["gson"]
//rxjava和网络
api rootProject.ext.dependencies["rxjava"]
api rootProject.ext.dependencies["rxandroid"]
api rootProject.ext.dependencies["retrofit"]
api rootProject.ext.dependencies["convertergson"]
api rootProject.ext.dependencies["rxjava2adapter"]
api rootProject.ext.dependencies["logginginterceptor"]
//图片加载
api rootProject.ext.dependencies["glide"]
//黄油刀
annotationProcessor rootProject.ext.dependencies["butterknife_compiler"]
api rootProject.ext.dependencies["butterknife"]
//权限
api rootProject.ext.dependencies["permission"]
api 'com.flyco.tablayout:FlycoTabLayout_Lib:2.1.2@aar'
implementation project(path: ':uilibrary')
}
把原来自己原来封装的baseActivity 、网络等一些内容移动进来
![](https://img.haomeiwen.com/i16265745/ad6a9530b7d76d2d.png)
这样我们对commonLib的封装就完成了
2.业务模块的封装
每个不同的app都有着自己不同封装,这个是需要根据具体的逻辑来的 就让我们先看一下原理的界面来抽出不同的业务模块。
先看具体界面
![](https://img.haomeiwen.com/i16265745/bad814c4b5a02386.png)
最终一共分为五个模块、
home:入口+首页模块
answer:答题测试模块
shop:积分商城模块
me:个人中心模块
commonActiivty:需要在四个模块中都需要用到的模块 如登录注册 等
业务模块遇到的问题
1.butterknife问题
application的gradle中添加 classpath 'com.jakewharton:butterknife-gradle-plugin:9.0.0'
需要在每个模块的gradle中添加
apply plugin: 'com.jakewharton.butterknife
dependencies {
annotationProcessor rootProject.ext.dependencies["butterknife_compiler"]
}
2.Arouter配置问题
一定要早每一个module中都要配置
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
includeCompileClasspath = true
}
}
3.application和library转换问题
在module的gradle中添加根据config中多的isModule判断是集成模式还是单个运行模式
if (Boolean.valueOf(rootProject.ext.isModule)) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
4.资源文件问题
在给资源文件命名的时候一定要以当前的module为前缀
5.不同xml问题
根据模式判断加载那个xml
在module/AndroidManifest.xml'下面要记得配置入口啊
sourceSets {
main {
if (Boolean.valueOf(rootProject.ext.isModule)) {
manifest.srcFile 'src/main/module/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
java {
//排除java/debug文件夹下的所有文件
exclude '*module'
}
}
}
最后上传组件化demo: https://github.com/525642022/ComponentApplication