目录
1.右键主工程包-> New -> File ,将文件名定义成config.gradle。
介绍
需求背景
随着项目逐渐扩展,业务功能越来越多,代码量越来越多,开发人员数量也越来越多,随之而来的就是各种各样的烦恼:
-
项目模块多且复杂,编译一次要5分钟甚至10分钟?太慢不能
-
改了一行代码 或只调了一点UI,就要run整个项目,得再忍五到十分钟、
-
合代码经常发生冲突。
-
被人偷偷改了自己模块的代码。
-
做一个需求,发现还要去改动很多别人模块的代码。
-
别的模块已实现的类似功能,自己要用只能去复制一份代码再改改
-
“这个不是我负责的,我不管”,代码责任范围不明确
-
只做了一个模块的功能,但改动点很多,所以要完整回归测试
-
做了个需求,但不知不觉导致其他模块出现bug
概念
Android 组件化是一种软件架构设计模式,旨在将大型 Android 应用划分为多个独立的、可重用的组件。这种模式的目标是提高应用的可维护性、可测试性,并允许团队独立开发和部署不同的功能模块。
接下来我给大家介绍一下 Android 组件化的一般原则和关键概念:
-
模块化设计: 将整个应用划分为多个模块(Module),每个模块负责特定的功能或业务。这些模块可以是独立的 Android 模块,也可以是 Java 模块。每个模块都应该是相对独立的单元,有着清晰的职责和接口。
-
组件间通信: 模块之间的通信是组件化的关键。一种常见的方法是使用事件总线(Event Bus)或者通过定义接口进行通信。这样,每个模块可以独立开发、测试和调试,而不需要了解其他模块的内部实现。
-
清晰的模块边界: 模块之间的边界应该清晰定义,避免直接的依赖关系。模块应该通过接口或者事件进行交互,而不是直接引用对方的类。这有助于减少模块间的耦合,提高模块的可维护性。
-
动态加载: 一些组件化架构支持模块的动态加载和卸载。这意味着你可以在应用运行时动态添加或移除模块,而不需要重新构建整个应用。这样的设计使得应用更加灵活,可以根据需要动态调整功能。
-
独立部署: 每个模块可以独立开发、测试和部署。这种独立性允许不同的团队或者开发者专注于他们负责的模块,而不需要关心整个应用的细节。
-
路由管理: 组件化中经常涉及到页面跳转和路由管理。一些组件化框架提供了路由表和路由管理的功能,使得组件之间的页面跳转更加方便。
-
共享资源: 在组件化中,可能存在一些需要共享的资源,比如图片、字符串、样式等。合理的资源管理对于确保各个模块之间协同工作很重要。
-
模块化工具: 有一些第三方工具和框架可以帮助实现 Android 组件化,例如 ARouter、Dagger、Koin 等。这些工具提供了一些方便的工具和约定,用于简化组件化的实现。
总体来说,Android 组件化是一种有助于构建可扩展、易维护、团队分工明确的 Android 应用的设计模式。在构建大型应用或者需要多团队协同开发的场景下,采用组件化架构可以提高项目的可维护性和开发效率。
意义
1.降低代码耦合。项目增大后易失去层次感,容易出现不同业务间的代码互相调用,高度耦合。组件化则可以实现各模块间不相互依赖,但可以互相交互、任意组合,高度解耦。
2.减少编译时间。项目代码越多编译时间越长。而组件化可以分模块打包进行编译测试。
3.提高代码复用率。不同业务间可能会出现重复的基础代码,但是并没有被抽离出来进行复用。组件化可以将基础组件或功能抽离出来进行复用(到新项目)。
4.提高团队开发效率。多人协作开发时,可能会由于代码风格不同而互相影响,也可能会增加代码版本管理成本或沟通成本。组件化将功能按照模块划分后可以一定程度上减轻以上问题从而提高效率。
区分模块化与组件化
模块化是将一个程序按照其功能做拆分,成为相互独立的模块,以便于每个模块只包含与其功能相关的内容,模块我们相对熟悉,比如登录功能可以是一个模块,搜索功能可以是一个模块等等。
组件化是模块化思想的一种演进,它们二者本质都是一致的。
组件化更注重关注点分离,所谓的关注点分离,就是把复杂的问题做到合理分解,再分别仔细研究这些问题的不同侧面(关注点),最后综合得到整体解决方案。
如果从集合角度来看的话,可以说往往一个模块包含了一个或多个组件,或者说模块是一个容器,由组件组装而成。简单来说,组件化相比模块化粒度更小。
组件化要考虑的问题
分而治之,并行开发,一切皆组件。要实现组件化,无论采用什么样的技术方式,都需要考虑以下几个方面的问题:
组件分层:如何将一个庞大的项目工程分成有机的整体?
组件单独运行和集成调试:每个组件都是高度内聚的,是一个完整的整体,如何让其单独运行和调试?在开发解读如何做到按需编译组件?
组件间通信:每个组件具体实现细讲都互相不了解,但每个组件都需要给其他调用方法提供服务,那么主项目与组件、组件与组件之间如何通信就变成关键?
组件生命周期:这里的生命周期指的是组件在应用中存在的时间,组件是否可以做到按需、动态使用,因此就会涉及到组件加载、卸载等管理问题。
组件分层
组件大致分层如下:主工程、业务组件层、功能组件层、基础组件层。
组件化的搭建与配置
创建组件module
首先,新建一个项目,作为我们的主工程,名字随便起,它是整个应用的主入口。对项目做一些初始化和配置都是在主工程里。
创建业务组件
右击主工程包-> New -> Module ,创建我们的第一个业务组件,这里Studio会自动为我们创建一个moduleCore包,这就是我们的业务组件层,所有业务组件都放在这里。
接下来我们再创建一个业务组件
创建功能组件
创建基础组件
File --> New --> New Module --> Android Library。
在Module name栏中加一个moduleBase,创建的基础组件都放在该文件夹下。同样在Package name栏加上一个module避免命名冲突。
创建完成后结果如下:
管理组件分层的依赖关系
首先,我们得对依赖做一个统一的管理,避免因版本不一致而产生的依赖冲突。这么多的module,它可能去依赖各种第三方库、SDK。因此,这里先做一个版本的管理。
1.右键主工程包-> New -> File ,将文件名定义成config.gradle。
ext{
isRelease = true
androidId = [
compileSdk : 33,
minSdk : 24,
targetSdk : 33,
versionCode : 1,
versionName : "1.0"
]
appId = [
app : "com.example.componentdemo",
first : "com.example.module.first",
second : "com.example.module.second"
]
dependencies = [
"appcompat" : "androidx.appcompat:appcompat:1.4.1",
"material" : "com.google.android.material:material:1.5.0",
"constraintlayout" : "androidx.constraintlayout:constraintlayout:2.1.3",
]
}
2.在根目录下的builde.gradle文件应用ext
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.0.2' apply false
id 'com.android.library' version '8.0.2' apply false
}
apply from: 'config.gradle'
3.修改基础组件的builde.gradle文件
plugins {
id 'com.android.library'
}
def androidId = rootProject.ext.androidId
def appId = rootProject.ext.appId
def support = rootProject.ext.dependencies
android {
namespace 'com.example.module.libbase'
compileSdk androidId.compileSdk
defaultConfig {
minSdk androidId.minSdk
targetSdk androidId.targetSdk
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
api support.appcompat
api support.material
api support.constraintlayout
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
4.修改业务组件和功能组件的builde.gradle
first包下的builde.gradle
if (isRelease){
apply plugin : 'com.android.library'
}else {
apply plugin : 'com.android.application'
}
def androidId = rootProject.ext.androidId
def appId = rootProject.ext.appId
def support = rootProject.ext.dependencies
android {
namespace 'com.example.module.first'
compileSdk androidId.compileSdk
defaultConfig {
if(!isRelease){
applicationId appId.first
}
minSdk androidId.minSdk
targetSdk androidId.targetSdk
versionCode androidId.versionCode
versionName androidId.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation project(":moduleBase:libBase")
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
second包下的builde.gradle
if(isRelease){
apply plugin : 'com.android.library'
}else {
apply plugin : 'com.android.application'
}
def androidId = rootProject.ext.androidId
def appId = rootProject.ext.appId
def support = rootProject.ext.dependencies
android {
namespace 'com.example.module.second'
compileSdk 33
defaultConfig {
if(!isRelease){
applicationId appId.second
}
minSdk androidId.minSdk
targetSdk androidId.targetSdk
versionCode androidId.versionCode
versionName androidId.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation project(":moduleBase:libBase")
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
功能组件略
5.修改app包下的build.gradle文件
plugins {
id 'com.android.application'
}
def androidId = rootProject.ext.androidId
def appId = rootProject.ext.appId
def support = rootProject.ext.dependencies
android {
namespace 'com.example.componentdemo'
compileSdk androidId.compileSdk
defaultConfig {
applicationId appId.app
minSdk androidId.minSdk
targetSdk androidId.targetSdk
versionCode androidId.versionCode
versionName androidId.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
if (isRelease){
implementation project(":moduleCore:first")
implementation project(":moduleCore:second")
}
implementation project(":moduleBase:libBase")
annotationProcessor 'com.alibaba:arouter-compiler:1.5.2'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
6.修改不同模式下的AndroidManifest 文件
当处于集成化环境时,整个应用打包成一个 apk,程序入口在 app 模块中,但当切换成组件化模式时,子模块单独打包为一个 apk,需要指定一个入口 Activity,并且配置 Application 标签下的相关内容,因此采用通过 sourceSets 指定源集的方式指定不同环境下所使用的 AndroidManifest 文件。
我以first包为例,右击main包,新建一个debug文件夹,将first包下的AndroidManifest文件复制一份粘贴到debug文件夹下,修改原来的AndroidManifest文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ComponentDemo">
<activity
android:name=".FirstActivity"
android:exported="true" />
</application>
</manifest>
debug文件夹下AndroidManifest文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ComponentDemo">
<activity
android:name=".FirstActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
接下来修改first包下的builde.gradle文件,添加如下代码
sourceSets{
main{
if(isRelease){
manifest.srcFile 'src/main/AndroidManifest.xml'
}else {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
}
}
}
完整builde.gradle文件代码
if (isRelease){
apply plugin : 'com.android.library'
}else {
apply plugin : 'com.android.application'
}
def androidId = rootProject.ext.androidId
def appId = rootProject.ext.appId
def support = rootProject.ext.dependencies
android {
namespace 'com.example.module.first'
compileSdk androidId.compileSdk
defaultConfig {
if(!isRelease){
applicationId appId.first
}
minSdk androidId.minSdk
targetSdk androidId.targetSdk
versionCode androidId.versionCode
versionName androidId.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets{
main{
if(isRelease){
manifest.srcFile 'src/main/AndroidManifest.xml'
}else {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
}
}
}
}
dependencies {
implementation project(":moduleBase:libBase")
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
业务组件里的所有组件都需要这么修改,本文本项目还需要修改second包里的文件。这里省略。
到这里,组件化创建工程就以完成。当把工程下下的build.gradle里的ext里的isRelease
改成flase时,就可以单独运行moduleCore.first或者moduleCore.second。记得Sync Now噢!
当工程下的build.gradle里的ext里的isRelease为true时
下一篇内容Android组件化基础(二)——组件间的通信-CSDN博客
本章参考了博客Android 组件化基础(一)—— 概述与基本配置_组件化在项目中的意义-CSDN博客