Android组件分包
今日目标
- 掌握组件分包的2种核心思路(按功能分包、按业务分包)及实战方法。
- 精通组件化工程全维度规范(命名、代码、配置、依赖),完成现有组件化工程的分包重构与规范优化。
- 规避分包和规范相关的高频踩坑点,提升工程可维护性、可扩展性和团队协作效率。
组件分包
价值
- 解决组件内部结构混乱、代码冗余、维护成本高、团队协作低效的痛点。
- 实现组件内部高内聚、组件之间低耦合,让项目结构清晰、可维护、可扩展。
- 同时降低新人上手成本,提升团队协作效率。
2种分包思路
- 按功能分包
- 按业务分包
按功能分包
- 将组件内部代码按功能模块划分:ui、model(数据模型)、tool、service、api、res等。
- 适用于小型组件或单一组件。
- 功能划分清晰、上手简单。
按业务分包
- 将组件内部代码按具体业务场景划分:例user组件分为login、register、detail、setting等。
- 适合大型组件或业务复杂组件。
- 业务隔离彻底、后续迭代维护便捷。
选型建议
- 基础组件:优先按功能分包,功能相对固定,侧重复用。
- 业务组件:优先按业务分包,业务迭代频繁,侧重隔离。
- 小型项目:先按功能分包,熟练后过渡到业务分包。
- 大型项目:统一采用
按业务分包为主、功能分包为辅的混合模式,兼顾业务隔离和功能复用。
分包实战
本示例以壳工程+base+user为例,base组件按功能分包、user组件按业务分包。实际项目按自身架构调整分包。
每个组件内按“ui(页面)、model(数据模型)、repository(数据仓库)、tools(工具)、common(公共资源)”划分目录,结构统一。
准备工作
- 1.梳理现有项目结构,避免重构混乱
- base组件:工具类、接口、实体类、资源文件等。
- user组件:Activity、接口实现、工具类、资源文件等。
- 分包目的:不改变原有功能,仅优化结构。
- 2.统一分包命名规范,提前约定,避免混乱
- 功能分包命名
- ui:基础UI相关(例:BaseActivity、BaseFragment、通用控件)
- model:实体类、数据模型(例:UserInfo、BaseResponse)
- tools:通用工具类(例:SPTool、MMKVTool、CoroutineTool)
- service:存储公共接口(例:IUserService、IComponentLifecycle)
- api:网络请求相关
- core:存储核心配置(例:Application、AppContext等)
- res:资源文件(按Android原生规范划分,drawable、layout、values等)
- 业务分包命名:以user为例
- login:登录相关(LoginActivity、登录工具类、登录数据处理类)
- detail:用户详情相关(UserDetailActivity、详情相关数据处理类)
- common:user组件公共内容(UserServiceImpl、UserComponentLifecycle等)
- res:user组件专属资源文件
base组件按功能分包
base组件作为基础组件,功能相对固定,按功能分包,重点实现功能模块化、代码复用。
- 1.创建base组件分包目录
// 在base组件的java/com/xxx/base目录下,创建以下分包目录(按功能划分):
// 1. ui:基础UI相关
// 2. model:实体类、数据模型
// 3. tools:通用工具类
// 4. service:公共接口
// 5. core:核心配置
// 目录结构如下:
base/
├── java/com/xxx/base/
│ ├── ui/ // 基础UI
│ ├── model/ // 实体类
│ ├── tools/ // 工具类
│ ├── service/ // 公共接口
│ └── core/ // 核心配置
└── res/ // 基础资源
- 2.迁移代码至对应分包
- 3.检查代码,确认包名引用修改为新包名,混淆保留代码使用新包名路径
- 4.同步项目打包验证
user组件按业务分包
user组件作为业务组件,业务迭代频繁,按业务分包,实现业务隔离,方便后续迭代维护。
- 1.创建user组件分包目录
// 在user组件的java/com/example/user目录下,创建以下分包目录(按业务划分):
// 1. login:登录相关
// 2. userDetail:用户详情相关
// 3. common:user组件公共内容
// 目录结构如下:
user/
├── java/com/xxx/user/
│ ├── login/ // 登录业务
│ ├── detail/ // 用户详情业务
│ └── common/ // 公共内容
└── res/ // 业务专属资源
- 2.迁移代码至对应分包
- 3.检查代码,确认包名引用修改为新包名,混淆保留代码使用新包名路径
- 4.同步项目打包验证
项目规范
- 命名规范
- 代码规范
- 配置规范
- 依赖规范
命名规范
核心原则:见名知意、统一格式、避免歧义。遵循驼峰命名规范。
- 1.包名规范
- 基础格式:
com.公司名.项目名或com.公司名.组件名 - 分包包名:
基础格式.分包名 - 禁止:包名使用拼音、无意义字母,禁止大小写混乱
- 基础格式:
- 2.类名规范
- Activity:Activity后缀,首字母大写(例:LoginActivity)
- Fragment:Fragment后缀,首字母大写(例:UserDetailFragment)
- 工具类:Tool后缀,首字母大写(例:SPTool、MMKVTool)
- 实体类:无后缀,首字母大写(例:UserInfo、BaseResponse)
- 接口:I开头,首字母大写(例:IUserService、IComponentLifecycle)
- 单例类:可加Manager后缀(例:FlowBusManager、ComponentLifecycleManager)
- 禁止:类名使用缩写(除非通用缩写,如MMKV、ARouter)、无意义名称
- 3.方法名规范
- 方法名首字母小写,驼峰命名,见名知意
- 点击事件:on+控件名+Click(例:onLoginBtnClick)
- 数据读写:get+数据名、put+数据名(例:getString、putParcelable)
- 初始化:init+功能名(例:initMMKV、initARouter)
- 禁止:方法名使用无意义字母、拼音,禁止方法名过长或过短
- 4.变量名规范
- 首字母小写,驼峰命名,见名知意
- 控件变量:控件类型缩写+控件功能(例:tvUserName、btnLogin)
- 常量:全大写,下划线分隔(例:VAL_MAX_COUNT = 10)
- 禁止:变量名使用单个字母(例:a、b)、拼音,禁止变量名与类名重复
- 5.资源文件规范
- 布局文件:组件名_业务名_功能名(例:user_login_activity、base_common_layout)
- 控件id:控件类型缩写_功能名(例:tv_user_name、btn_login)
- 图片资源:组件名_功能名_状态(例:user_avatar_default、base_ic_back)
- 字符串资源:组件名_功能名(例:user_login_title、base_toast_success)
- 禁止:资源文件使用中文、无意义名称,禁止不同组件资源重名(可加组件前缀区分)
资源命名优化:将user组件的所有资源添加user_前缀
- 布局文件:user_login_activity.xml、user_profile_fragment.xml
- 图片资源:ic_user_avatar.png、ic_user_setting.png
- 字符串资源:<string name="user_login_title">登录</string>
- 避免与base组件、其他业务组件资源冲突。
代码规范
核心原则:简洁、规范、可复用、无冗余。借助CheckStyle插件辅助规范检查。
- 1.代码格式规范
- 缩进:4个空格(Android Studio默认),禁止使用Tab缩进
- 空行:方法之间、类之间留1行空行,逻辑块之间留1行空行,避免连续空行
- 括号:if、for、while等语句的括号紧跟关键字(
if (condition) {),第一行语句另起一行 - 注释:关键逻辑、复杂方法添加注释(// 单行注释,/** 多行注释 */),注释简洁明了,禁止无用注释
- 2.代码复用规范
- 重复代码:提取为工具类或公共方法(例:多次使用的字符串处理、弹窗逻辑)
- Activity/Fragment:继承base组件的BaseActivity/BaseFragment,统一初始化操作
- 工具类:统一放入base组件tools分包,避免各组件重复创建工具类
- 3.代码冗余规范
- 删除无用代码:注释掉的代码、未使用的方法、变量,及时删除
- 简化代码:使用Kotlin特性(例:空安全、扩展函数、lambda表达式)简化代码,避免冗余
- 4.异常处理规范
- 关键逻辑(例:数据读写、网络请求)添加异常捕获(try-catch),避免崩溃
- 禁止:直接catch Exception,需针对性捕获具体异常(例:NullPointerException、IOException)
配置规范
核心原则:集中管理、统一配置,贴合Version Catalog依赖管理规范,避免配置分散
- 1.版本配置规范:所有依赖版本、插件版本,统一在Version Catalog(
gradle/libs.versions.toml)中管理,禁止硬编码版本 - 2.构建配置规范
- 所有组件的compileSdk、minSdk、targetSdk,统一通过Version Catalog引用,确保版本一致
- 壳工程统一配置签名、buildTypes(debug/release),各组件无需重复配置
// 示例:base组件build.gradle中,compileSdk引用Version Catalog版本
android {
...
compileSdk {
version = release(libs.versions.compileSdk.get().toInt()) {
minorApiLevel = 1
}
}
defaultConfig {
minSdk = libs.versions.minSdk.get().toInt()
targetSdk = libs.versions.targetSdk.get().toInt()
...
}
}
...
- 3.ARouter配置规范
- 路由path格式:/组件名/页面名(例:/user/UserLoginActivity、/main/MainActivity)
- 路由extras统一管理,避免随意设置,便于拦截器中实现页面拦截
- 所有路由页面添加@Route注解,确保路径唯一,无冲突
- 4.Hilt配置规范
- 单例类添加@Singleton注解,Module类添加@Module、@InstallIn注解,确保注入正常
- 组件间注入的接口,统一在base组件service分包中定义,避免接口分散
- 禁止:重复提供Hilt实例,避免注入冲突
- 5.混淆配置规范
- 全局混淆(壳工程)配置公共规则,组件混淆配置专属规则
- 混淆规则按包名保留,避免逐个类保留(如-keep class com.xxx.base.** {*;})
- 新增分包后,检查混淆规则,确保所有核心类(工具类、接口、实体类)不被混淆
依赖规范
核心原则:依赖统一、隔离清晰、无冗余,避免依赖混乱。
- 1.依赖引用规范:所有依赖均通过Version Catalog(libs.xxx)引用,禁止硬编码依赖
- 2.依赖类型规范
- base组件:公共依赖用api暴露(如ARouter、MMKV),内部依赖用implementation
- 业务组件(user):仅依赖base组件,内部依赖用implementation,禁止使用api
- 壳工程:仅依赖base和业务组件,不直接引入第三方依赖,避免重复引入
- 3.依赖冗余规范
- 定期清理无用依赖(Android Studio会提示unused),同步清理Version Catalog中的冗余配置
- 避免重复引入同一依赖(例:base组件已暴露ARouter,user组件无需再引入)
- 4.依赖兼容规范
- 确保第三方依赖与Android Gradle插件、Kotlin版本兼容(通过Version Catalog统一管理版本)
- 新增依赖时,先在Version Catalog中配置,再引用,确保版本统一
综合测试
对分包重构和规范优化后的工程进行全面测试,确保功能正常、规范达标、可正常上线。
- 测试核心:覆盖分包后所有功能,验证分包和规范的合理性,确保无报错、无功能失效
测试范围
- 1.debug模式测试
- 运行壳工程,逐一测试以下功能:
- ① ARouter路由:页面跳转(MainActivity→LoginActivity、MainActivity→UserActivity)、参数传递正常;
- ② Hilt依赖注入:IUserService接口、GlobalDataManager单例注入正常,接口调用正常;
- ③ 数据共享:DataStore、MMKV、全局单例的跨组件数据读写正常;
- ④ 组件生命周期:App启动、退出时,组件加载、卸载正常,日志打印正常;
- ⑤ 所有分包模块:代码可正常调用,无包名错误、引用错误;
- 验证规范:检查项目命名、代码格式、配置、依赖,确保符合规范要求。
- 2.release模式测试
- 配置签名,运行release版本,重复debug模式的所有测试用例;
- 验证要点:release模式下所有功能正常,无混淆失效、依赖冲突,包体积正常;
- 重点验证:分包后ARouter路由、Hilt注入、MMKV数据存储功能正常,无报错。
踩坑点
坑点1:分包后包名引用错误,导致编译报错
- 原因:代码迁移后未修改包名引用,或包名拼写错误。
- 修复:检查并修正所有代码的包名引用、包名拼写,同步修改ARouter、Hilt相关注解的包名,确保一致。
坑点2:分包后ARouter路由跳转失败
- 原因:路由path冲突、页面包名修改后未同步更新路由注解,或ARouter未注入。
- 修复:检查路由path唯一性,同步更新路由注解的包名,确保Activity继承BaseActivity(统一ARouter注入)。
坑点3:分包后Hilt注入为null
- 原因:单例类/接口的包名修改后,未同步修改Hilt Module中的引用,或Activity未添加@AndroidEntryPoint注解。
- 修复:更新Hilt Module中的包名引用,确保所有需要注入的Activity添加@AndroidEntryPoint。
坑点4:分包过细或混乱,导致维护效率降低
- 原因:未明确分包思路,盲目拆分。
- 修复:遵循“按功能/业务分包”原则,base模块按功能、业务组件按业务,避免过度拆分,确保分包结构清晰、合理。
坑点5:规范不统一,命名、代码格式混乱
- 原因:未提前约定规范,或执行不彻底。
- 修复:制定统一的工程规范手册,逐一检查优化,养成规范编码习惯,增加review环节检查代码。
坑点6:分包后依赖冗余,导致依赖冲突
- 原因:业务组件重复引入base组件已暴露的依赖。
- 修复:清理业务组件中的重复依赖,确保仅依赖base组件,所有第三方依赖通过base组件api暴露,或通过Version Catalog统一管理。