Android—组件化的搭建
1.什么是组件化?
1.1 为什么要用组件化
在项目的开发过程中,随着开发人员的增多及功能的增加,如果提前没有使用合理的开发架构,那么代码会越来臃肿,功能间代码耦合也会越来越严重,这时候为了保证项目代码的质量,我们就必须进行重构
1.2 组件化的介绍
组件化是指解耦复杂系统时将多个功能模块拆分,重组的过程。在Android工程上表现上就是把app按照其业务的不同,划分为不同的Module
1.3 组件化的优点
编译速度 :我们可以按需测试单一模块极大的提升了我们的开发速度
超级解耦 :极度的降低了模块之间的耦合,便于后期维护与更新
功能重用 : 某一块的功能在另外的组件化项目中使用只需要单独依赖这一模块即可
便于团队开发 : 组件化架构是团队开发必然会选择的一种开发方式,它能有效的使团队更好的协作
1.4 组件化的框架
先看一下整体的结构
举个例子:以某个直播平台为例(没有画完整),
基础层:包含的是一些基础库以及对基础库的封装,比如常用的图片加载,网络请求,数据存储操作等等,其他模块或者组件都可以引用同一套基础库,这样不但只需要开发一套代码,还解耦了基础功能和业务功能的耦合,在基础库变更时更加容易操作。
功能组件层:包含一些简单的功能组件,比如视频,支付等等
业务组件层:这是通过模块化划分出来的,即根据业务的不同划分为不同的模块,一个具体的业务模块会按需引用不同的组件,最终实现业务功能,如上有三个业务组件
app层:多个业务模块,各自按需引用组件,最后将各个模块统筹输出 APP
2.组件化框架的搭建
2.1 gradle文件统一管理版本号
在主模块下创建config.gradle文件夹(可以不是config但后缀必须是gradle),依赖库,项目中sdk等等的版本号把有重用的地方都放在这里,以后的每个模块的版本号都要引用这里的
在主模块的build.gradle中加载config.gradle
2.2.修改创建的项目app(也叫app壳工程)
创建BaseApplication类文件
public class BaseApplication extends Application { @Override public void onCreate() { super.onCreate(); Log.d("app","baseApplication"); } }
需要注意的点AndroidManifest.xml一定要指定name
修改app工程的build.gradle文件
plugins { id 'com.android.application' } android { compileSdk rootProject.ext.android.compileSdkVersion defaultConfig { applicationId rootProject.ext.android.applicationId minSdk rootProject.ext.android.minSdkVersion targetSdk rootProject.ext.android.targetSdkVersion versionCode rootProject.ext.android.versionCode versionName rootProject.ext.android.versionName testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner } 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 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' implementation rootProject.ext.dependencies.appcompatV7 implementation rootProject.ext.dependencies.constraintLayout implementation fileTree(dir: 'libs', include: ['*.jar']) // isModule = false 表示集成 if (!rootProject.ext.isModule) { implementation project(":ModuleMain") } }
2.3 ModuleMain的搭建
2.3.1创建modlue (new module选择 Android Library)
2.3.2创建MainApplication类
public class MainApplication extends Application { @Override public void onCreate() { super.onCreate(); Log.d("application","MainApplication"); } }
2.3.3 统一版本号处理(修改build.gradle)
修改build.gradle最上面plugins如下
//通过isModule来判断是application还是module if (rootProject.ext.isModule) { //application :可独立运行的Android程序,也就是我们的APP apply plugin: 'com.android.application' } else { //library :不可以独立运行,一般是Android程序依赖的库 apply plugin: 'com.android.library' }
AndroidManifest.xml文件的区分
在main目录下新建manifest文件夹,在该文件夹下新建AndroidManifest.xml,作为单独调试的AndroidManifest.xml
main/manifest/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.sy.moduledemo" xmlns:tools="http://schemas.android.com/tools"> <application android:name="com.example.sy.moduledemo.MainApplication" tools:replace="android:allowBackup" android:allowBackup="true" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/Theme.ComponentDemo" tools:ignore="GoogleAppIndexingWarning"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
在main目录下的AndroidManifest.xml作为集成调试
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.sy.moduledemo" xmlns:tools="http://schemas.android.com/tools"> <application tools:replace="android:allowBackup" android:allowBackup="false"> <activity android:name=".MainActivity"></activity> </application> </manifest>
然后在 build.gradle 中通过判断rootProject.ext.isModule的值,来配置不同的 ApplicationId 和 AndroidManifest.xml 文件的路径
sourceSets { main { if (rootProject.ext.isModule) { manifest.srcFile 'src/main/manifest/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' } } }
defaultConfig { if (rootProject.ext.isModule) { applicationId 'com.example.sy.moduledemo' } minSdk rootProject.ext.android.minSdkVersion targetSdk rootProject.ext.android.targetSdkVersion versionCode rootProject.ext.android.versionCode versionName rootProject.ext.android.versionName testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner }
完整的build.gradle
//通过isModule来判断是application还是module if (rootProject.ext.isModule) { //application :可独立运行的Android程序,也就是我们的APP apply plugin: 'com.android.application' } else { //library :不可以独立运行,一般是Android程序依赖的库 apply plugin: 'com.android.library' } android { compileSdk rootProject.ext.android.compileSdkVersion defaultConfig { if (rootProject.ext.isModule) { applicationId 'com.example.sy.moduledemo' } minSdk rootProject.ext.android.minSdkVersion targetSdk rootProject.ext.android.targetSdkVersion versionCode rootProject.ext.android.versionCode versionName rootProject.ext.android.versionName testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner } 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 (rootProject.ext.isModule) { manifest.srcFile 'src/main/manifest/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' } } } } dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' implementation rootProject.ext.dependencies.appcompatV7 implementation rootProject.ext.dependencies.constraintLayout implementation fileTree(dir: 'libs', include: ['*.jar']) }
2.3.4 通过修改config.gradle中isModule 值来组件化单一启动和依赖集成 启动
2.4 组件的跳转
2.4.1ARoute 是阿里的开源库 ;
在app 和moduleMain模块下都需要如下配置
在 build.gradule下的 " android / defaultConfig " 层级添加配置 :
android { defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] } } } }
在 build.gradule下的 " android / defaultConfig " 层级添加配置 :
// 替换成最新版本, 需要注意的是api // 要与compiler匹配使用,均使用最新版可以保证兼容 api 'com.alibaba:arouter-api:1.5.1' annotationProcessor 'com.alibaba:arouter-compiler:1.5.1'
2.4.2app跳转到moduleMain模块的页面
app 模块 : 使用 @Route(path = "/app/MainActivity")
注解标注 Activity 类 , 界面按钮点击方法跳转到 moduleMain中的 Activity 界面中 ;
/** * // 在支持路由的页面上添加注解(必选) * // 这里的路径需要注意的是至少需要有两级,/xx/xx */ @Route(path = "/app/mainActivity") public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button m_v1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); m_v1 = findViewById(R.id.m_v1); m_v1.setOnClickListener(this); } @Override public void onClick(View v) { if(v==m_v1){ ARouter.getInstance().build("/module/MainActivity").navigation(); } } }
app主模块要完成route的初始化
public class BaseApplication extends Application { @Override public void onCreate() { super.onCreate(); ARouter.init(this); Log.d("app","baseApplication"); } }
moduleMain模块跳转的activity添加注解
@Route(path = "/module/MainActivity") public class ModuleMainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_module_main); } }
*需要注意的点app的activity和moduleMain的activity不能同名否则会跳转失效