Skip to content

工程目录结构

项目初创

一个 Android 项目创建后,会生成一套默认的目录结构,它也是 Android 工程体系与 Gradle 构建系统的基础。

典型结构如下:

my-android-project/
├── app/
│   ├── build/
│   ├── libs/
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/
│   │   │   ├── kotlin/
│   │   │   ├── res/
│   │   │   └── AndroidManifest.xml
│   │   ├── test/
│   │   └── androidTest/
│   ├── build.gradle
│   └── proguard-rules.pro
├── build.gradle
├── settings.gradle
└── gradle/
    └── wrapper/

在实际开发中,大多数目录结构都是围绕 main 与 res 展开的,其中最核心的部分通常是:

  • 包名目录
  • 资源目录

其中 res 目录本身具备固定规则,而项目中最容易随着业务增长不断演化的,往往是包名目录结构。

res 资源目录

基本轮廓如下,文件和文件夹新增都是有固定规则的。“一些目录下的资源文件需要有命名规范后续会提到”

res/
├── drawable/                   
├── drawable-xxhdpi/            
├── layout/                     
├── values/                     
│   ├── strings.xml             
│   ├── colors.xml              
│   └── styles.xml              
├── mipmap/                     
└── raw/

谷歌官方指南:《资源目录存放指引》

因此,本文重点讨论的是:如何合理组织包名目录结构。

包名目录

main 目录下,如果项目是 Java 和 kotlin 混开,那么可以:

  • 分别存放在 javakotlin 目录中
  • 统一 java 目录。

当项目规模较大、两种语言文件较多时,更推荐按语言拆分:

main/java/
    └──com/example/myapp
main/kotlin
    └──com/example/myapp

两个目录下的包结构应保持一致。

🚫 重要注意事项

不建议将 Java 文件放在 kotlin 目录下。

虽然部分 Gradle 或 Kotlin 插件版本能够正常编译,但在不同 AGP、IDE 或构建配置下,可能出现索引异常、类缺失或构建行为不一致的问题。

推荐保持:

  • Java 文件放在 java/
  • Kotlin 文件放在 kotlin/

统一目录职责,避免潜在兼容性问题。

基础目录结构

包名目录的层级设计,会直接影响项目的:

  • 可维护性
  • 可扩展性
  • 阅读效率
  • 团队协作成本

一个常见的基础结构如下:

com/example/myapp/

├── app/              # Application、全局初始化、全局变量
├── base/             # 存放各个组件的通用基类(取名 base/basic 均可)
│   ├── activity/
│   ├── fragment/
│   ├── dialog/
│   ├── holder/
│   └── ...
├── consts/           # 全局常量
├── model/            # 数据模型
├── ui/
│   ├── activity/
│   ├── fragment/
│   ├── dialog/
│   ├── adapter/
│   │   └── holder/
│   ├── widget/
│   └── ...
├── utils/            # 工具类
└── ...

即使是中小型项目,也通常建议具备基础目录分层。

随着业务扩展,再逐步细化。

注意

避免在项目初期过度拆分目录。

目录结构的目标是降低理解成本,而不是追求层级数量。

如果一个目录长期只包含少量文件,或拆分后无法带来明显收益,应优先保持简单结构。


避免将 utils 逐渐演变成“杂项目录”。

工具类应具备明确职责与边界,不相关逻辑不要持续堆积在同一个目录中。

当工具类开始明显增长时,应进一步拆分:

常见目录扩展

除了基础结构外,实际项目中还会根据:

  • Android 组件
  • 第三方框架
  • 架构设计
  • 业务规模

继续扩展目录层级。

组件目录

Android 四大组件 除 Activity 通常放在 ui 下外,其余组件一般会独立管理。

  • Service
com/example/myapp/
            ├──app/
            ├──.../
            └──services/ # 管理各个服务组件
  • BroadcastReceiver
com/example/myapp/
            ├──app/
            ├──.../
            └──receivers/ # 管理各个广播组件(全局和本地广播都在此存放)
  • ContentProvider
com/example/myapp/
            ├──app/
            ├──.../
            └──providers/ # 管理各个内容提供器组件

第三方框架

当第三方框架开始产生:

  • 配置类
  • 扩展类
  • 适配层
  • 自定义实现

通常会单独建立一级目录。

Glide 图片加载框架

当 Glide 仅作为简单图片加载库使用时,不一定需要单独目录。

但如果已经开始:

  • 自定义 Module
  • 自定义 Loader
  • 编译期配置
  • 网络适配

则建议:

com/example/myapp/
            └──glide/ # 存放glide框架相关的配置类

用于统一管理 Glide 相关配置。

网络请求库

当网络层逐渐复杂后,通常会统一抽象:

com/example/myapp/
            └──http/
                ├── api/
                ├── interceptor/
                ├── server/
                ├── response/
                └── ...

当网络相关能力开始集中后,像 Glide 网络配置这类内容,也可以归入网络层统一管理。

数据库

例如 Room:

com/example/myapp/
            └──db/
               ├──dao/ # dao 层分类
               ├──entity/ # 相关实体类
               └──.../

依赖注入

例如:

  • Hilt
  • Dagger
  • Koin

通常会建立:

com/example/myapp/
            └──di/ # 依赖注入

其他目录

串口通信

com/example/myapp/
            └──serial/
                ├── config/     # 串口配置
                ├── manager/    # 串口管理
                ├── listener/   # 数据监听
                ├── protocol/   # 通信协议
                └── parser/     # 数据解析

自定义注解

com/example/myapp/
            └──annotation/ # 存放自定义的注解类

Kotlin 扩展函数

com/example/myapp/
            └──extensions/ # 存放扩展函数文件

任务类

com/example/myapp/
            └──tasks/ # 存放各个任务类

目录扩展原则

通过以上目录扩展可以发现,新增一级目录通常遵循以下原则。

1. 单一职责原则

每一级目录应聚焦单一职责。

避免将不相关逻辑混合存放。

2. 功能聚合原则

目录应围绕:

  • 功能模块
  • 技术能力
  • 业务领域

进行聚合。

3. 可维护性和可扩展性

目录结构应具备扩展空间。

新增功能时,能够自然融入,而不是不断推翻原有结构。

例如:

service/
model/
http/

都具备天然扩展能力。

4. 避免横向膨胀

当一级目录数量开始明显增多时,应考虑:

  • 模块聚合
  • 业务分层
  • feature 化

而不是无限新增一级目录。

避免最终出现:

/user
/order
/pay
/chat
/video
/home
/profile

导致根目录持续膨胀。

架构目录扩展

目录结构最终应服务于架构设计。

不同架构下,目录划分也会有所区别。

MVVM 分层结构

这个架构的详细内容可具体参见官方文档:https://developer.android.com/topic/architecture?hl=zh-cn

基于 Repository 的 MVVM 分层是目前较常见的一种组织方式,它会将:

  • UI
  • 数据源
  • 数据仓库
  • ViewModel

进行职责拆分。

典型结构如下:

com/example/myapp/
            ├── model/
            ├── sources/
            │   ├── local/        # 本地 api 接口和实现类
            │   ├── remote/       # 远端 api 接口和实现类
            │   └── repository/   # 存放数据仓库接口和实现类
            ├── viewmodel/
            └── ui/

这种结构的核心目标是:

  • ViewModel 更轻量
  • 数据来源更清晰
  • 业务职责更明确

注意

不要让 ViewModel 同时承担:

  • UI 控制
  • 业务逻辑
  • 数据处理
  • 网络请求

否则本质上只是换了一种形式继续耦合。

模块化目录结构

当项目规模继续扩大后,可以进一步演化为模块化结构。

模块化之后,目录划分会更加偏向:

  • 业务域
  • 能力域
  • 基础设施层

而不仅仅是简单的功能分类。

总结

工程目录结构没有绝对标准。

真正合理的目录结构,应当:

  • 清晰
  • 稳定
  • 易维护
  • 易扩展

目录的意义,不是追求 “分类越多越专业”,而是让项目能够随着业务增长依然保持可读性与可控性。

演进

在实际开发中,应根据:

  • 项目规模
  • 团队人数
  • 架构复杂度
  • 业务特点

不断调整与演进目录结构,不要一味的机械套用固定模板。

基于 MIT 许可发布