目录
1.为什么要使用组件化
在我们写项目的时候,简单的小项目,小功能可以由我们一个人自己简单进行实现,但是一旦功能较多较复杂的时候一个人就难以实现,在现在随着APP的不断迭代更新,每个APP都有很多功能,新的功能也在不断出现。APP在不断变得庞大,APP内的业务也开始变得难以维护,这样发展下去,将会出现很多难以处理的问题,比如**可维护性差,开发效率低,缺乏灵活性和可扩展性,测试和调试困难,**所以必须要有更灵活的架构代替过去单一的工程架构。在这样的情况下组件化的出现就显的十分重要,项目组件化是一种软件架构设计的方法,将一个大型项目拆分为多个小的可独立开发、测试和维护的组件。
之前的架构,往往是在一个界面中存在大量的业务逻辑,而业务逻辑中充斥着各种网络请求、数据操作等行为。可能有些程序员有意识将不同功能的部分分隔开来,但是还是难以将其彻底分隔开来,所以各个模块之间还是高度耦合的,这样不断迭代下来,整个项目就可能高度耦合为一个整体难以实现各个部分的修改,维护成本变得极为高昂,在多人共同协同开发时,每个人都需要理解整个项目的所有代码。影响开发效率。
组件化架构让各个业务变得相对独立,业务组件在组件模式下可以独立开发,将其而在集成模式下又可以变为arr包集成到“app壳工程”中,组成一个完整功能的APP;
- 代码组织方式:组件化架构通过将功能模块划分为独立的组件,每个组件具有清晰的职责和接口,便于代码组织和管理。而在不使用组件化架构的情况下,代码可能以传统的单体结构组织,所有功能模块都集中在一起,导致代码结构复杂混乱。
- 模块化程度:组件化架构强调模块化设计,将功能拆分为独立的组件,并通过接口进行通信和交互。这样可以提高代码的可维护性和可测试性,也方便并行开发和团队协作。而不使用组件化架构的项目可能缺乏明确的模块划分,导致代码耦合性高,修改某个功能可能会影响其他部分的代码。
- 可重用性:组件化架构鼓励将通用的功能封装成可复用的组件,以便在不同的项目中重复使用。这样可以提高代码的复用性,减少重复编写相似功能的工作量。相比之下,不使用组件化架构的项目可能存在重复编写功能代码的问题,导致代码冗余。
- 扩展性和灵活性:组件化架构使得项目更具扩展性和灵活性。当需要添加新的功能或调整现有功能时,只需关注特定的组件,而不必修改整个项目。这样可以减少引入错误和增加维护成本的风险。而在不使用组件化架构的项目中,改动一个功能可能需要修改多处相关代码,增加了开发风险和工作量。
2.什么是组件化
在上面讲述了组件化的好处,但是只是单纯的知道了组件化是将一个项目分为多个小组件但是并不了解什么是组件化,这里开始正式介绍组件化
组件化是一种软件架构设计方法,它将整个软件系统划分为多个独立的功能模块,每个模块都被作为一个单独的组件进行开发、测试和部署。这些组件可以是独立的可执行文件、动态链接库、静态库、甚至是服务或微服务,它们之间通过明确的接口和协议进行通信。使得整个软件系统也做到电路板一样,是单个或多个组件元件组装起来,哪个组件坏了,整个系统可继续运行,而不出现崩溃或不正常现象,做到更少的耦合和更好的内聚。
组件化和模块化的区别
上面说到了从普通的无架构到组件化,这里有一个模块化和组件化的区别问题,模块化和组件化的本质区别又是什么?为了解决这些问题,我们就要先了解 “模块” 和 “组件” 的区别。
模块
模块指的是独立的业务模块,比如微信中的发现模块和我的模块 等。
组件
组件指的是单一的功能组件,如 [支付组件] 等,每个组件都可以以一个单独的 module 开发,并且可以单独抽出来
由此来看,[模块] 和 [组件] 间最明显的区别就是模块相对与组件来说粒度更大,一个模块中可能包含多个组件。并且两种方式的本质思想是一样的,都是为了代码重用和业务解耦。在划分的时候,模块化是业务导向,组件化是功能导向。
组件化的分层
这个部分有很多不同的分层,大致分层如下:主工程、业务组件层、功能组件层、基础组件层。
- 主工程层:主工程是整个软件系统的入口点,它负责将各个组件进行整合和协调。主工程通常包含一些公共的配置、路由或者框架代码,用于管理和启动其他组件。
- 业务组件层:业务组件层是针对具体业务需求而设计的组件。每个业务组件都承担着特定的业务功能,例如用户管理、订单处理、支付等。业务组件层负责实现业务逻辑,并与其他组件进行交互。
- 功能组件层:功能组件层是为了提供通用的功能和服务而设计的组件。这些组件可以被多个业务组件共享和复用,例如身份验证、日志记录、缓存等。功能组件层的目标是促进组件之间的解耦和代码重用。
- 基础组件层:基础组件层是最底层的组件,包含了一些核心的基础设施和工具。它们通常提供底层的功能支持,如数据库访问、网络通信、文件操作等。基础组件层为上层组件提供了必要的基础服务。
这里我偷到了一位博主的一张图([博客链接](Android—组件化_android 组件化-CSDN博客))
大致了解一下组件化的思想(他是一种思想并不是一种具体的知识),现在开始具体的实现
具体实现
1.创建module
1.创建一个新的项目,我的项目名字是modulestudy(这个无所谓),作为上面提到的主工程,程序入口(创建自带的"app")
2.创建俩个业务组件,一个main,一个login,File->new->new Module->Phone&Tablet
这里这个组件名字叫main,为了更好的管理,这里在Module name栏中加一个moduleCore,后面创建的所有业务组件都放到moduleCore文件夹下面。在Package name栏加一个module,避免命名冲突的一些问题。
这里我使用的是java,无法选择Empty Actvity,所以选择No Activity 在创建完我会创建一个主活动,后续都会创建主活动,然后就会变为下面的样子
另一个可以在moduleCore中new创建Module,创建一个名字为login的组件
3.创建功能组件
4.创建基础组件
此时他就会变成这样
现在你就可以在各个组件中编写你的代码了,但是很快你就会发现一些问题,如何进行各个组件的依赖处理,现在我需要对他进行一个统一的处理,这就是下面的内容。
2. 动态配置组件的工程类型?
在AndroidStudio 开发 Android 项目时,使用的是 Gradle 来构建,他提供了三种插件,来对应不同的开发模式
-
App ,id: com.android.application
-
Library ,id: com.android.libraay
-
Test ,id: com.android.test
第一个app,他是用于构建Android 应用程序的并将当前应用程序编译为APK文件并部署到设备上运行
第二个Library,他是用于构建 Android 库的。可以将代码打包成可重用的库,供其他应用程序或库使用。
第三个text,用于构建测试模块,它用来编写和运行针对应用程序模块的单元测试、集成测试或功能测试
在这里我们主要使用其中的俩个,即第一个和第二个,通过工程的 build.gradle 文件中依赖的插件 id 可以配置工程的类型如
apply plugin :'com.android.application'
但是组件要求既可以单独调试又可以被其他模块依赖,所以这里的id就需要动态的改变,所以我们在project下的build.gradle中设置一个变量,通过这个变量来动态的设置id,通过改变这个id来实现不同的调试模式
同时在单独调试和集成调试时组件的 ApplicationId 应该是不同的;一般来说一个 APP 也应该只有一个启动页, 在组件单独调试时也是需要有一个启动页,在集成调试时如果不处理启动页的问题,主工程和组件的 AndroidManifes 文件合并后就会出现两个启动页,这个问题也是需要解决的。这些问题父解决思路和上面是一样都是通过这个变量来控制
1.在project下的build.gradle里创建一个ext{},里面添加如下内容。
ext{
isDebug = true //当它为true时,是调试模式,组件可以单独运行(applicaton);当它为false,是正式的编译打包的模式(library). 作业:使得业务组件可以在application和library之间进行切换
android = [//这些变量若在创建module时注意版本控制,可以选择不进行特意设置
compileSdkVersion: 33,
minSdkVersion: 27,
targetSdkVersion: 33,
buildToolsVersion: "30.0.2",
versionCode: 1,
versionName: "1.0"
]
applicationId = [ // 可以切换到application
"app" : "com.example.component",
"main" : "com.example.module.main",
"login" : "com.example.module.login"
]
// SDK的一写library
library = [
"appcompat" : "androidx.appcompat:appcompat:1.3.0",
"material" : "com.google.android.material:material:1.4.0",
"constraintlayout" : "androidx.constraintlayout:constraintlayout:2.0.4"
]
//第三方的library
libARouter = "com.alibaba:arouter-api:1.5.1"
libARouterCompiler = "com.alibaba:arouter-compiler:1.5.1"
libGson = "com.google.code.gson:gson:2.8.6"
}
这里只是作为一个例子,不同的项目需要导入不同的依赖库,后面就是在不同的组件中导入这个build.gradle的数据
2.在moduleCore中的组件修改build.gradle
if(isDebug.toBoolean())//这里是进行判断此时的状态
{
apply plugin :'com.android.application'
}else
{
apply plugin :'com.android.library'
}
def cfg = rootProject.ext//定义变量得到Project下的build.gradle中的ext
android {
namespace 'com.example.module.main'
compileSdk cfg.android.compileSdkVersion//使用cfg中的变量替换
defaultConfig {
if(cfg.isDebug)
{
applicationId cfg.applicationId.main
}
minSdk cfg.android. minSdkVersion//使用cfg中的变量替换
targetSdk cfg.android.targetSdkVersion//使用cfg中的变量替换
versionCode cfg.android.versionCode//使用cfg中的变量替换
versionName cfg.android.versionName//使用cfg中的变量替换
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 {//这个是为了处理AndroidManifest.xml'的问题,
main{
if(cfg.isDebug)
{
manifest.srcFile 'src/mian/debug/AndroidManifest.xml'
}else {
manifest.srcFile 'src/mian/AndroidManifest.xml'
}
}
}
}
dependencies {
implementation project(':moduleBase:main')//导入的数据(不仅仅是依赖)
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
当main/login是一个applicaton (isDubug==true时, 可以单独运行)时,对AndroidManifest.xml文件也要进行修改。
首先,在mian下面创建一个debug文件夹,然后拷贝一份AndroidManifest.xml 到里面
其次,将main下面的AndroidManifest.xml 做修改(注意:不是修改debug下的那个AndroidManifest.xml)(是为了不将该活动作为启动页面)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.module.main">
<application
>
<activity
android:name=".MainActivity"
android:exported="true" />
</application>
</manifest>
最后就是上面的
sourceSets {
main{
if(cfg.isDebug)
{
manifest.srcFile 'src/mian/debug/AndroidManifest.xml'
}else {
manifest.srcFile 'src/mian/AndroidManifest.xml'
}
}
}
3.修改 libBase基础组件 里的build.gradle文件
apply plugin : 'com.android.library'
def cfg= rootProject.ext
android {
namespace 'com.example.module.libase'
compileSdk cfg.android.compileSdkVersion
defaultConfig {
minSdk cfg.android.minSdkVersion
targetSdk cfg.android.targetSdkVersion
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 {
//导入cfg中的依赖
api cfg.library.appcompat
api cfg.library.material
api cfg.library.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.修改 modulabilable功能组件 里的build.gradle文件。
apply plugin : 'com.android.library'
def cfg= rootProject.ext
android {
namespace 'com.example.module.modulepay'
compileSdk cfg.android.compileSdkVersion
defaultConfig {
minSdk cfg.android.minSdkVersion
targetSdk cfg.android.targetSdkVersion
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 {
implementation project(':moduleBase:liBase')
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 cfg= rootProject.ext
android {
namespace 'com.example.module'
compileSdk cfg.android.compileSdkVersion
defaultConfig {
applicationId "com.example.module"
minSdk cfg.android.minSdkVersion
targetSdk cfg.android.targetSdkVersion
versionCode cfg.android.versionCode
versionName cfg.android.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:liBase')
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
现在修改isDebug,
就可以看到
这里提出一个问题,为什么只有moduleCore的俩个组件没有其他俩个层次的组件,答案就交给你自己去找了