# ComponentDemo **Repository Path**: developer_wind/ComponentDemo ## Basic Information - **Project Name**: ComponentDemo - **Description**: kotlin组件化项目,商城组件,user组件 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-04 - **Last Updated**: 2026-06-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Android Component Demo 一个**基础实战**的 Android Kotlin 组件化学习项目。 本仓库同时演示两种常见写法,方便对照: | 业务 | 模块 | 组件化方式 | |------|------|------------| | 商城 | `component-mall` | **普通组件化**(一个 Library 搞定) | | 用户 | `user-api` + `user-impl` | **API + Impl**(接口与实现分开) | 更系统的讲解见:[Android 组件化学习项目(Kotlin + AGP8+).md](./Android%20组件化学习项目(Kotlin%20+%20AGP8+).md) 技术栈:AGP 8+、Kotlin、Library 多模块、`ServiceManager`、Router、组件初始化与通信。 --- # 一、先搞懂:什么叫「组件」? 可以把每个 **Library 模块** 想成公司里的一个**业务部门**: - **对外只办一件事**:比如「打开用户页」「打开商城页」 - **内部自己管页面、数据**:Activity、Repository 别人不该随便闯进去 - **主工程 app** 像「总部」:负责把各部门拼进 APK,并在启动时「点名报到」(初始化) 组件化要解决的问题就一句: > **总部(app)需要用人家的能力,但不应该绑死在人家内部的 Activity 类名上。** --- # 二、项目结构总览 ```txt ComponentDemo │ ├── app 主工程(壳、首页、组装依赖) ├── common 公共能力(所有模块都能用) ├── component-mall 商城组件(普通组件化) ├── user-api 用户组件 · 对外契约 ├── user-impl 用户组件 · 具体实现 └── component-user 旧版用户组件(已停用,仅作对照) ``` | 模块 | Gradle 类型 | 一句话职能 | |------|-------------|------------| | `app` | application | 安装包入口;依赖各组件;在 `Application` 里初始化 | | `common` | library | 公共基类、`ServiceManager`、工具类,**不含业务** | | `component-mall` | library | 商城业务:页面、数据、`MallService` 对外入口 | | `user-api` | library | 用户**对外说明书**:`IUserService`、`UserRouter` | | `user-impl` | library | 用户**真正干活**:Activity、实现类、注册服务 | | `component-user` | library(已注释) | 旧写法,与 `user-api/impl` 对照用 | --- # 三、各模块职能详解 ## 3.1 `app` —— 主工程 / 壳 **干什么:** - 生成可安装的 APK - 首页 `MainActivity` 上放按钮,决定「点哪个组件」 - `App.kt` 里统一调用 `UserComponent.init()`、`MallComponent.init()` - `AppRouter` 可集中封装跳转(商城走这里) **不该干什么:** - 不要堆大量业务逻辑(应下沉到各组件) - 尽量不要 `Intent(this, UserActivity::class.java)` 这种**直连别人内部页面**的写法(用户组件已用接口规避) --- ## 3.2 `common` —— 公共模块 **干什么:** | 类 / 能力 | 作用(通俗说) | |-----------|----------------| | `ServiceManager` | 小型「服务台」:谁注册了什么接口,从这里取 | | `BaseActivity` | 各业务 Activity 的公共父类,少写重复代码 | | `IService` | 旧式组件服务标记(商城 `MallService` 在用) | | `ToastUtils`、`RouterPath` | 工具与路由常量,给各模块复用 | **依赖关系:** 被 `app`、`component-mall`、`user-api`、`user-impl` 引用;**自己不依赖任何业务组件**。 --- ## 3.3 `component-mall` —— 商城组件(普通组件化) **目录里有什么:** ```txt component-mall ├── api/MallService.kt 对外入口:start() 打开商城页 ├── ui/MallActivity.kt 商城页面 ├── repository/ 取商品数据 ├── data/Product.kt 数据模型 └── MallComponent.kt 组件初始化(打日志等) ``` **职能:** 商城这一块业务**打包在一个模块**里;app 依赖整个 `component-mall`,通过 `MallService.start(context)` 使用。 **特点(好懂版):** - ✅ 简单、上手快,适合小功能、学习第一阶段 - ⚠️ app 理论上能 `import` 到 `MallActivity`,容易写成「面向实现」、耦合偏高 **本项目中怎么调用:** ```kotlin // AppRouter.kt MallService.start(context) ``` --- ## 3.4 `user-api` + `user-impl` —— 用户组件(API + Impl) 把用户能力拆成「**合同**」和「**施工队**」: ### `user-api`(合同 / 对外能力) | 文件 | 职能 | |------|------| | `IUserService` | 接口:只声明「能打开用户页」等能力,不含实现 | | `UserRouter` | 统一入口:`UserRouter.service()` 从 `ServiceManager` 取服务 | **谁该依赖它:** app、其他业务模块、甚至别的 APP(只想要能力、不想绑死实现时)。 ### `user-impl`(施工队 / 内部实现) | 文件 | 职能 | |------|------| | `UserServiceImpl` | 实现 `IUserService`,内部 `startActivity` 到 `UserActivity` | | `UserActivity` | 用户界面 | | `UserRepository`、`User` | 数据与逻辑 | | `UserComponent` | `init()` 时把 `UserServiceImpl` **注册**进 `ServiceManager` | **谁该依赖它:** 主工程要打出完整 APK 时必须带上(Activity、Manifest 要进包);第三方也可换成自己的 impl。 **本项目中怎么调用(推荐):** ```kotlin UserRouter.service().openUser(this) ``` **对比错误写法:** ```kotlin // 不推荐:app 直接认识 UserActivity,耦合高 startActivity(Intent(this, UserActivity::class.java)) ``` --- # 四、两大业务组件对比(核心) | 维度 | 商城 `component-mall` | 用户 `user-api` + `user-impl` | |------|------------------------|-------------------------------| | 模式 | 普通 Library 组件化 | API + Impl 分离 | | 对外入口 | `MallService` 对象 | `IUserService` 接口 + `UserRouter` | | 编程思想 | 偏「面向实现」 | 偏「面向接口」 | | app 依赖 | `implementation(:component-mall)` | `user-api` + `user-impl` | | 替换实现 | 较难(整包绑定) | 可换 impl 或自研实现再 `register` | | 适用场景 | 小团队、快速开发、学习入门 | 大项目、多团队、要解耦与扩展 | | 企业阶段 | 组件化入门 | 企业组件化**第一阶段** | 用生活例子记: - **Mall**:你点外卖,店家给你一个固定电话(`MallService`),打过去就行,简单。 - **User**:你只认「能送用户页」这份**协议**(`IUserService`),具体哪家快递(`UserServiceImpl`)在启动时登记到服务台(`ServiceManager`),以后可以换快递而不改总部代码。 --- # 五、引用关系(Gradle + 代码,两层都要懂) ## 5.1 Gradle 依赖(编译期「谁引用谁」) ```txt ┌─────────────┐ │ app │ └──────┬──────┘ ┌───────────────┼───────────────┐ │ │ │ ▼ ▼ ▼ ┌────────────┐ ┌────────────┐ ┌──────────────┐ │ common │ │ user-api │ │ component- │ └────────────┘ └─────┬──────┘ │ mall │ │ └──────┬───────┘ ▼ │ ┌────────────┐ │ │ user-impl │──────────┘(各自依赖 common) └────────────┘ │ └──► 只依赖 user-api,不依赖 mall ``` `app/build.gradle.kts` 里当前大致是: ```kotlin implementation(project(":common")) implementation(project(":user-api")) implementation(project(":user-impl")) implementation(project(":component-mall")) ``` **重点:** - `user-impl` → 只依赖 `user-api` + `common`(实现依赖接口,符合依赖倒置) - `user-api` → **不**依赖 `user-impl`(合同不依赖施工队) - `app` → 为打完整包,既要 `user-api`(调用),也要 `user-impl`(页面进 APK) ### 为什么有了 api,app 还要依赖 impl? 这是**静态组件化**:编译期就把所有模块打进 APK,不是插件化。 - `UserActivity`、布局、`AndroidManifest` 必须在 impl 里,并参与编译 - 不依赖 impl → 容易 `ActivityNotFoundException` - 依赖 impl ≠ 代码里可以随意 `import UserActivity`;**规范上**仍应只通过 `UserRouter` 调用(企业里还会用 lint、Code Review 约束) `implementation` **不会**在语言层面禁止你 import impl 的类,靠的是**团队约定 + 架构意识**。 --- ## 5.2 代码调用(运行期「谁找谁」) ### 用户组件:注册 → 获取 → 调用 ```mermaid sequenceDiagram participant App participant UserComponent participant ServiceManager participant MainActivity participant UserRouter App->>UserComponent: init() 注册服务 UserComponent->>ServiceManager: register(IUserService, UserServiceImpl) MainActivity->>UserRouter: service() UserRouter->>ServiceManager: get(IUserService) ServiceManager-->>MainActivity: openUser() ``` 1. `App.onCreate()` → `UserComponent.init()`(**漏了会 NPE**:接口没注册) 2. 按钮点击 → `UserRouter.service().openUser(this)` 3. `UserServiceImpl` 内部再打开 `UserActivity` `AndroidManifest.xml` 里必须配置: ```xml ``` 否则 `Application` 不执行,初始化也不会跑。 ### 商城组件:直接调 Service ```txt MainActivity → AppRouter.openMall() → MallService.start() → MallActivity ``` 没有 `ServiceManager`,路径更短,也更容易和内部类缠在一起。 --- # 六、ServiceManager 是干什么的? 可以把它想成**公司前台的服务登记表**: ```kotlin // 登记(user-impl 里 UserComponent.init) ServiceManager.register(IUserService::class.java, UserServiceImpl()) // 取用(user-api 里 UserRouter.service) ServiceManager.get(IUserService::class.java) ``` 作用: - 各组件把自己的实现「挂」到统一地方 - 调用方只认接口类型,不 new 具体实现类 - 类似简化版 **IoC 容器**,是企业组件化里很常见的一步 --- # 七、主工程里实际怎么点按钮 ## 用户 ```kotlin UserRouter.service().openUser(this) ``` `App.kt`: ```kotlin UserComponent.init() ``` ## 商城 ```kotlin AppRouter.openMall(this) // 内部 MallService.start(context) ``` `App.kt`: ```kotlin MallComponent.init() ``` --- # 八、第三方 APP 如何引用组件 ## 源码依赖(学习推荐) `settings.gradle.kts` 引入:`common`、`user-api`、`user-impl`(或自研 impl)、`component-mall`。 ```kotlin implementation(project(":user-api")) implementation(project(":user-impl")) // 需要官方完整能力时 ``` `Application` 里:`UserComponent.init()`,调用方式与主工程相同。 只想要契约、自己写页面时:**只依赖 `user-api`**,自实现 `IUserService` 并 `ServiceManager.register()`。 ## AAR 依赖(贴近企业发布) ```bash gradlew :user-api:assembleRelease gradlew :user-impl:assembleRelease gradlew :component-mall:assembleRelease ``` 产物在各自模块的 `build/outputs/aar/` 下,拷到对方 `libs/` 并 `implementation(files(...))`,注意 **common 等传递依赖** 也要带上或改为 Maven 发布。 --- # 九、常见问题(通俗版) | 现象 / 疑问 | 原因 | 怎么办 | |-------------|------|--------| | `openUser` 空指针 | `UserComponent.init()` 没执行 | 检查 `App` 与 Manifest `android:name` | | 明明 api+impl,app 还能 import `UserActivity` | Gradle `implementation` 不隔离源码可见性 | 遵守规范,用 `UserRouter`,企业加 lint | | 能不能 app 只依赖 api? | 静态打包下 Activity 必须在 impl | 要「只依赖 api」需动态化 / 插件化 | | Mall 和 User 用哪套? | 学习:两种都保留对比 | 新业务偏大团队优先 api+impl | --- # 十、组件开发规范(实战小结) * **契约放 `*-api`**:接口、Router * **实现放 `*-impl` 或单模块的 `api` 包**:Activity、Repository、`XxxComponent.init()` * **页面跳转走 Service / Router**,宿主不直连组件内部 Activity * **公共能力只放 `common`** * **所有组件在 `Application` 统一初始化** --- # 十一、推荐学习路线(与本项目对应) 1. **普通组件化** → 先看 `component-mall`、`MallService` 2. **API + Impl** → 再看 `user-api`、`user-impl` 3. **ServiceManager + Router** → 理解注册与 `UserRouter` 4. 之后可学:自动注册、组件独立运行、动态组件化、插件化(见学习文档第二十六节) --- # 十二、这个项目到底值在哪? 不只是「多建了几个 module」,而是练: * 模块边界、依赖方向 * 面向接口 vs 面向实现 * 服务注册与组件通信 * 静态组件化下 api / impl 的真实分工 **一句话:** 组件化的核心不是拆了多少个模块,而是**让调用方不绑死在具体实现上**。 --- # 十三、后续可扩展 * `component-mall` 升级为 `mall-api` / `mall-impl` * ARouter、KSP 自动注册、组件独立调试、动态化 / 插件化 --- # 十四、适合谁读 * Android 组件化入门与进阶 * 需要在一个仓库里**对照两种组件写法** * 准备接触企业多模块架构的同学 详细章节化讲义:[Android 组件化学习项目(Kotlin + AGP8+).md](./Android%20组件化学习项目(Kotlin%20+%20AGP8+).md)