文章目录
Android 组件化设计
什么是组件化
库 & 模块 & 组件 的区别:
- 库:提供单一功能或一些功能。
- 模块:指具体的业务逻辑模块,一个App可根据业务拆分为多个模块,如微信就定义了四个模块:微信、通讯录、发现、我。
- 组件:指功能组件或业务组件,每个组件可以独立运行,功能组件如:视频组件、支付组件、数据组件等,业务组件如:登陆组件等。
组件化优点:
- 在单工程项目中,各种业务代码混杂在一块,不方便后续的迭代、维护、调试,且代码复用性差。
- 在组件化中,将App剥离开,分成多个模块,每个模块都是一个组件,一定程度上解决了代码的耦合问题,且组件是可以单独运行的,方便调试。
由此可见,模块和组件的最明显的区别是模块相对于组件来说粒度更大,一个模块可能包含多个组件。
开始组件化操作
自定义Gradle
定义一个config.gradle文件
ext {
//独立运行组件开关
isModule = false
android = [
compileSdkVersion : 30,
buildToolsVersion : "30.0.3",
minSdkVersion : 21,
targetSdkVersion : 30,
versionCode : 1,
versionName : "1.0",
applicationId : "com.example.app",
applicationId_chat : "com.example.chat",
applicationId_contact: "com.example.contact",
applicationId_find : "com.example.find",
applicationId_me : "com.example.me"
]
dependencies = [
//Kotlin
"kotlin-stdlib" : "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version",
"core-ktx" : 'androidx.core:core-ktx:1.3.1',
//Android
"appcompat" : 'androidx.appcompat:appcompat:1.3.1',
"material" : 'com.google.android.material:material:1.2.1',
"constraintlayout": 'androidx.constraintlayout:constraintlayout:2.0.1',
//ARouter
"arouter-api" : 'com.alibaba:arouter-api:1.5.2',
"arouter-compiler": 'com.alibaba:arouter-compiler:1.5.2',
//CircleImageView
"circleimageview" : 'de.hdodenhof:circleimageview:3.0.0',
//ShapeView
"shapeView" : 'com.github.getActivity:ShapeView:8.0',
//Eventbus
"eventbus" : 'org.greenrobot:eventbus:3.2.0'
]
}
并添加到项目下的build.gradle中
apply from: "config.gradle"
创建其他组件
通过 Flie -> New Module -> Android Library 依次创建:
配置app主工程
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
buildToolsVersion rootProject.ext.android["buildToolsVersion"]
defaultConfig {
applicationId rootProject.ext.android["applicationId"]
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
//开启ViewBinding
buildFeatures {
viewBinding = true
}
}
//ARouter
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(path: ':common')
if (!Boolean.valueOf(rootProject.ext.isModule)) {
implementation project(path: ':chat')
implementation project(path: ':contact')
implementation project(path: ':find')
implementation project(path: ':me')
}
//ARouter
implementation rootProject.ext.dependencies["arouter-api"]
kapt rootProject.ext.dependencies["arouter-compiler"]
}
配置common组件
配置Gradle:
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
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"]
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
}
kotlinOptions {
jvmTarget = '1.8'
}
}
//ARouter
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
//Kotlin
api rootProject.ext.dependencies["kotlin-stdlib"]
api rootProject.ext.dependencies["core-ktx"]
//Android
api rootProject.ext.dependencies["appcompat"]
api rootProject.ext.dependencies["material"]
api rootProject.ext.dependencies["constraintlayout"]
//ShapeView
api rootProject.ext.dependencies["shapeView"]
//CircleImageview
api rootProject.ext.dependencies["circleimageview"]
//Eventbus
api rootProject.ext.dependencies["eventbus"]
//ARouter
implementation rootProject.ext.dependencies["arouter-api"]
kapt rootProject.ext.dependencies["arouter-compiler"]
}
依次创建BaseApp、BaseActivity、BaseFragment等基类。
open class BaseApp : Application() {
companion object {
lateinit var context: Context
}
override fun onCreate() {
super.onCreate()
context = this
if (BuildConfig.DEBUG) {
ARouter.openLog()
ARouter.openDebug()
}
ARouter.init(this)
}
}
配置其他组件
这里以chat组件为例,其他都类似。
配置Gradle:
if (Boolean.valueOf(rootProject.ext.isModule)) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
buildToolsVersion rootProject.ext.android["buildToolsVersion"]
defaultConfig {
if (Boolean.valueOf(rootProject.ext.isModule)) {
applicationId rootProject.ext.android["applicationId_chat"]
}
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main {
if (Boolean.valueOf(rootProject.ext.isModule)) {
manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
java {
//library模式下,排除java/debug文件夹下的所有文件
exclude '*module'
}
}
}
}
//开启ViewBinding
buildFeatures {
viewBinding = true
}
}
//ARouter
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(path: ':common')
//ARouter
implementation rootProject.ext.dependencies["arouter-api"]
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
kapt rootProject.ext.dependencies["arouter-compiler"]
}
配置manifest文件:
src/main/AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.chat">
<application>
<activity
android:name=".RunChatActivity"
android:label="RunChatActivity" />
<activity android:name=".info.ChatInfoActivity" />
<activity android:name=".MyFragmentActivity" />
</application>
</manifest>
src/main/manifest/AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.chat">
<application
android:name=".base.ChatApp"
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.App">
<activity android:name=".RunChatActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".info.ChatInfoActivity" />
<activity android:name=".MyFragmentActivity" />
</application>
</manifest>
使用ARouter组件间跳转
定义跳转路径
Path路径至少是两个层级,同一组件第一级路径不能重复。
object ARouterConstant {
//chat组件
const val PATH_CHAT_RUN = "/Chat/RunChatActivity"
//contact组件
const val PATH_CONTACT_RUN = "/contact/RunContactActivity"
const val PATH_CONTACT_MY_ACTIVITY = "/contact/MyActivity"
//find组件
const val PATH_FIND_RUN = "/find/RunFindActivity"
const val PATH_FIND_FRAGMENT = "/find/FindFragment"
//me组件
const val PATH_ME_RUN = "/me/RunMeActivity"
}
注册
@Route(path = ARouterConstant.PATH_CHAT_RUN)
class RunChatActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_run_chat)
}
}
跳转
ARouter.getInstance().build(ARouterConstant.PATH_CHAT_RUN).navigation()
组件间通信
- EventBus
- 广播
资源冲突问题
最终所有组件都会合并在一起,为了防止资源重名问题,在项目下的build.gradle中定义一个前缀:
//资源冲突
subprojects {
afterEvaluate {
android {
resourcePrefix "${project.name}_"
}
}
}
添加前缀后,AS会约束我们在定义资源名时,但仍然需要我们手动添加上,对图片资源不会提示。