Android 组件化案例
01.组件化实践开源项目
- 关于组件化开发一点感想
- 关于网上有许多关于组件化的博客,讲解了什么是组件化,为何要组件化,以及组件化的好处。大多数文章提供了组件化的思路,给我着手组件化开发提供了大量的便利。感谢前辈大神的分享!虽然有一些收获,但是很少有文章能够给出一个整体且有效的方案,或者一个具体的Demo。
- 但是毕竟看博客也是为了实践做准备,当着手将之前的开源案例改版成组件化案例时,出现了大量的问题,也解决了一些问题。主要是学些了组件化开发流程。
- 大多数公司慢慢着手组件化开发,在小公司,有的人由于之前没有做过组件化开发,尝试组件化也是挺好的;在大公司,有的人一去只是负责某个模块,可能刚开始组件化已经有人弄好了,那学习实践组件化那更快一些。业余实践,改版之前开源项目,写了这篇博客,耗费我不少时间,要是对你有些帮助,那我就很开心呢。由于我也是个小人物,所以写的不好,勿喷,欢迎提出建议!
- 关于组件化开源项目
- 项目整体架构模式采用:组件化+MVP+Rx+Retrofit+design+Dagger2+VLayout+X5
- 包含的模块:wanAndroid【kotlin】+干货集中营+知乎日报+番茄Todo+精选新闻+豆瓣音乐电影小说+小说读书+简易记事本+搞笑视频+经典游戏+其他更多等等
- 此项目属于业余时间练手的项目,接口数据来源均来自网络,如果存在侵权情况,请第一时间告知。本项目仅做学习交流使用,API数据内容所有权归原作公司所有,请勿用于其他用途。
02.如何创建模块
- 根据架构设计图可以知道
- 主工程:
- 除了一些全局配置和主 Activity 之外,不包含任何业务代码。有的也叫做空壳app,主要是依赖业务组件进行运行。
- 业务组件:
- 最上层的业务,每个组件表示一条完整的业务线,彼此之间互相独立。原则上来说:各个业务组件之间不能有直接依赖!所有的业务组件均需要可以做到独立运行的效果。对于测试的时候,需要依赖多个业务组件的功能进行集成测试的时候。可以使用app壳进行多组件依赖管理运行。
- 该案例中分为:干活集中营,玩Android,知乎日报,微信新闻,头条新闻,搞笑视频,百度音乐,我的记事本,豆瓣音乐读书电影,游戏组件等等。
- 功能组件:
- 该案例中分为,分享组件,评论反馈组件,支付组件,画廊组件等等。同时注意,可能会涉及多个业务组件对某个功能组件进行依赖!
- 基础组件:
- 支撑上层业务组件运行的基础业务服务。此部分组件为上层业务组件提供基本的功能支持。
- 该案例中:在基础组件库中主要有,网络请求,图片加载,通信机制,工具类,分享功能,支付功能等等。当然,我把一些公共第三方库放到了这个基础组件中!
03.如何建立依赖
关于工程中组件依赖结构图如下所示
业务模块下完整配置代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60//控制组件模式和集成模式
if (rootProject.ext.isGankApplication) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
android {
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
buildToolsVersion rootProject.ext.android["buildToolsVersion"]
defaultConfig {
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
if (rootProject.ext.isGankApplication){
//组件模式下设置applicationId
applicationId "com.ycbjie.gank"
}
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
//jdk1.8
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
main {
if (rootProject.ext.isGankApplication) {
manifest.srcFile 'src/main/module/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
jniLibs.srcDirs = ['libs']
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':library')
annotationProcessor rootProject.ext.dependencies["router-compiler"]
}
04.如何统一配置文件
由于组件化实践中模块比较多,因此配置gradle,添加依赖库时,需要考虑简化工作。那么究竟如何做呢?
第一步,首先在项目根目录下创建一个yc.gradle文件。实际开发中只需要更改该文件中版本信息即可。
- 我在网上看到的绝大多数案例,都是通过一个开关控件组件模式和集成模式的切换,但是这里我配置了多个组件的开关,分别控制对应的组件切换状态。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44ext {
isApplication = false //false:作为Lib组件存在, true:作为application存在
isAndroidApplication = false //玩Android模块开关,false:作为Lib组件存在, true:作为application存在
isLoveApplication = false //爱意表达模块开关,false:作为Lib组件存在, true:作为application存在
isVideoApplication = false //视频模块开关,false:作为Lib组件存在, true:作为application存在
isNoteApplication = false //记事本模块开关,false:作为Lib组件存在, true:作为application存在
isBookApplication = false //book模块开关,false:作为Lib组件存在, true:作为application存在
isDouBanApplication = false //豆瓣模块开关,false:作为Lib组件存在, true:作为application存在
isGankApplication = false //干货模块开关,false:作为Lib组件存在, true:作为application存在
isMusicApplication = false //音乐模块开关,false:作为Lib组件存在, true:作为application存在
isNewsApplication = false //新闻模块开关,false:作为Lib组件存在, true:作为application存在
isToDoApplication = false //todo模块开关,false:作为Lib组件存在, true:作为application存在
isZhiHuApplication = false //知乎模块开关,false:作为Lib组件存在, true:作为application存在
isOtherApplication = false //其他模块开关,false:作为Lib组件存在, true:作为application存在
android = [
compileSdkVersion : 28,
buildToolsVersion : "28.0.3",
minSdkVersion : 17,
targetSdkVersion : 28,
versionCode : 22,
versionName : "1.8.2" //必须是int或者float,否则影响线上升级
]
version = [
androidSupportSdkVersion: "28.0.0",
retrofitSdkVersion : "2.4.0",
glideSdkVersion : "4.8.0",
canarySdkVersion : "1.5.4",
constraintVersion : "1.0.2"
]
dependencies = [
//support
"appcompat-v7" : "com.android.support:appcompat-v7:${version["androidSupportSdkVersion"]}",
"multidex" : "com.android.support:multidex:1.0.1",
//network
"retrofit" : "com.squareup.retrofit2:retrofit:${version["retrofitSdkVersion"]}",
"retrofit-converter-gson" : "com.squareup.retrofit2:converter-gson:${version["retrofitSdkVersion"]}",
"retrofit-adapter-rxjava" : "com.squareup.retrofit2:adapter-rxjava2:${version["retrofitSdkVersion"]}",
//这里省略一部分代码
]
}第二步,然后在项目中的lib【注意这里是放到基础组件库的build.gradle】中添加代码,如下所示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
buildToolsVersion rootProject.ext.android["buildToolsVersion"]
defaultConfig {
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
api rootProject.ext.dependencies["appcompat-v7"]
api rootProject.ext.dependencies["design"]
api rootProject.ext.dependencies["palette"]
api rootProject.ext.dependencies["glide"]
api (rootProject.ext.dependencies["glide-transformations"]){
exclude module: 'glide'
}
annotationProcessor rootProject.ext.dependencies["glide-compiler"]
api files('libs/tbs_sdk_thirdapp_v3.2.0.jar')
api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
//省略部分代码
}第三步,在其他model中添加依赖
- implementation project(‘:library’)即可。
05.组件化的基础库
- 基础库组件封装
- 基础库组件封装库中主要包括开发常用的一些框架。可以直接看我的项目更加直观!
- 1、网络请求(采用Retrofit+RxJava框架),拦截器
- 2、图片加载(策略模式,Glide与Picasso之间可以切换)
- 3、通信机制(RxBus),路由ARouter简单封装工具类(不同model之间通信)
- 4、mvp框架,常用的base类,比如BaseActivity,BaseFragment等等
- 5、通用的工具类,比如切割圆角,动画工具类等等
- 6、自定义view(包括对话框,ToolBar布局,圆形图片等view的自定义)
- 7、共有的shape,drawable,layout,color等资源文件
- 8、全局初始化异步线程池封装库,各个组件均可以用到
- 如何简化不熟悉组件化的人快速适应组件独立运行
- 设置多个组件开关,需要切换那个组件就改那个。如果设置一个开关,要么把所有组件切成集成模式,要么把所有组件切成组件模式,有点容易出问题。更多可以往下看!
- 严格限制公共基础组件的增长
- 随着开发不断进行,要注意不要往基础公共组件加入太多内容。而是应该减小体积!倘若是基础组件过于庞大,那么运行组件也是比较缓慢的!
06.组件和集成模式如何切换
在玩Android组件下的build.gradle文件,其他组件类似。
- 通过一个开关来控制这个状态的切换,module如果是一个库,会使用com.android.library插件;如果是一个应用,则使用com.android.application插件
1
2
3
4
5
6//控制组件模式和集成模式
if (rootProject.ext.isAndroidApplication) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}集成模式如下所示
- 首先需要在yc.gradle文件中设置 isApplication=false。Sync下后,发现该组件是library
1
2ext {
isAndroidApplication = false //false:作为Lib组件存在, true:作为application存在组件模式如下所示
- 首先需要在yc.gradle文件中设置 isApplication=true。Sync下后,发现该组件是application,即可针对模块进行运行
1
2ext {
isAndroidApplication = true //false:作为Lib组件存在, true:作为application存在需要注意的地方,这个很重要
- 首先看看网上绝大多数的作法,非常感谢这些大神的无私奉献!但是我觉得多个组件用一个开关控制也可以,但是sourceSets里面切换成组件app时,可以直接不用下面这么麻烦,可以复用java和res文件。
- 接下来看看我的做法:
- 下面这个配置十分重要。也就是说当该玩Android组件从library切换到application时,由于可以作为独立app运行,所以序意设置applicationId,并且配置清单文件,如下所示!
- 在 library 和 application 之间切换,manifest文件也需要提供两套
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18android {
defaultConfig {
if (rootProject.ext.isAndroidApplication){
//组件模式下设置applicationId
applicationId "com.ycbjie.android"
}
}
sourceSets {
main {
if (rootProject.ext.isAndroidApplication) {
manifest.srcFile 'src/main/module/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
jniLibs.srcDirs = ['libs']
}
}
}- 具体在项目中如下所示
- 首先看看网上绝大多数的作法,非常感谢这些大神的无私奉献!但是我觉得多个组件用一个开关控制也可以,但是sourceSets里面切换成组件app时,可以直接不用下面这么麻烦,可以复用java和res文件。