工程目录结构说明

    |     2015年4月19日   |   Android概述   |     0 条评论   |    1528

约定:minSdkVersion = 26、targetSdkVersion = 36、JDK 17、仅 Java、不用 Kotlin;Gradle 8.x + AGP 8.x;包名根 edu.cdp.android.dayNN。


1. 工程总览

在 Android Studio(AS)里新建 Empty Activity(注意选 Java 而不是 Kotlin)后,工程根目录一眼看上去并不复杂——和早年的 Eclipse 时代相比,已经清爽很多:

day01_helloworld/ ← 工程根 ├── build.gradle ← 项目级 Gradle 配置 ├── settings.gradle ← 模块包含关系 ├── gradle.properties ← Gradle 运行时参数 ├── gradlew / gradlew.bat ← Gradle Wrapper 启动脚本 ├── gradle/ │ └── wrapper/ │ └── gradle-wrapper.properties ← Wrapper 指定 Gradle 版本 ├── .gitignore └── app/ ← 应用模块(可改名,本课不动) ├── build.gradle ← 模块级 Gradle 配置 ├── proguard-rules.pro └── src/ └── main/ ├── AndroidManifest.xml ← 应用清单 ├── java/ ← 我们的 Java 源码 └── res/ ← 资源(图片、布局、字符串)

记住一条总原则:源码三件套——AndroidManifest.xml + java/ + res/——其他都是装配它们的「脚手架」。

区块 放什么 谁负责
根目录 Gradle 配置、Wrapper、.gitignore 项目级,本课基本不动
app/ 应用模块(源码 + 资源 + 清单) 我们写代码的主战场
app/src/main/ 真正能跑的应用源码 业务代码从这里开始
gradle/wrapper/ Wrapper 配置 保证不同机器用同一份 Gradle

2. 根目录关键文件

2.1 settings.gradle

声明这个工程包含哪些模块。本课只有一个 app:

pluginManagement { repositories { google() mavenCentral() gradlePluginPortal() } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } } rootProject.name = "Day01HelloWorld" include ':app'

include ':app' 这一行最常被本课修改——你改名模块就要同时改这里。

2.2 build.gradle(项目级)

放各模块共用的插件声明。本课常见配置:

plugins { id 'com.android.application' version '8.1.0' apply false id 'com.android.library' version '8.1.0' apply false }

版本号与 AGP 对应;第一节课用 AS 默认即可,不要主动改。

2.3 app/build.gradle(模块级)

这里的设置最影响 app 行为。要记住的字段:

字段 本课取值 含义
applicationId edu.cdp.android.day01.helloworld 应用的「身份证」(和包名相似,与 Java 包名可以不同)
minSdkVersion 26 最低支持到 Android 8.0
targetSdkVersion 36 编译时按最新版行为校验
compileSdkVersion 36 编译时使用的 SDK 版本
versionCode / versionName 1 / "1.0" 安装包升级用,本课固定即可

sourceCompatibility / targetCompatibility 用 JavaVersion.VERSION_17,对应 JDK 17。

2.4 gradle/wrapper/ 与 gradlew

  • gradlew / gradlew.bat:命令行执行入口。
  • gradle-wrapper.properties:记着「本工程固定用哪一版 Gradle」。

课堂约定:所有人用同一份 Wrapper,保证编译环境一致;遇到「Gradle 版本不匹配」的报错,先检查这台机器是不是用了 Wrapper,而不是全局 gradle。


3. app/ 模块:源码三件套

进入 app/src/main/,目录只有三种东西:清单、Java 代码、资源。

app/src/main/ ├── AndroidManifest.xml ← 清单:组件、权限、主题 ├── java/ │ └── edu/cdp/android/day01/helloworld/ │ └── MainActivity.java ← 一个 Activity = 一个 Java 类 └── res/ ← 资源,下一节单独讲 ├── layout/ ├── values/ └── mipmap-*/

3.1 AndroidManifest.xml(清单)

这是 app「登记」所有组件的地方。 不登记的 Activity,系统不会启动它。

最小化示例(AS 帮我们生成):

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.Day01"> <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>

要记的几条:

元素/属性 作用 本课是否动
<uses-permission> 申请权限(写文件、网络等) 第 7 日起需要时再加
<application android:theme> app 主题 第 14 日改 NoActionBar
<activity android:name> 类名,. 表示「相对 applicationId 的子包」 改名时同步改这里
<intent-filter> + MAIN / LAUNCHER 桌面图标点进来的入口 一个 app 只配一个

3.2 java/:Java 源码

  • 路径层次要和包名一一对应:package edu.cdp.android.day01.helloworld; 对应 java/edu/cdp/android/day01/helloworld/。
  • 一个文件一个顶层 public 类,文件名必须与类名一致。
  • 第 1 日就一个 MainActivity.java,第 4 日起按课程约定的子包结构拆。

3.3 res/:资源

下一节单独讲。


4. res/ 资源子目录

res/ 放 App 资源(图片、布局、文字、主题……)。这些文件会在编译期编入 R.java,运行时用资源 ID(R.string.app_name、R.layout.activity_main)引用——比直接传字符串安全得多。

目录 放什么 备注
res/layout/ 布局 XML(activity_main.xml) 第 2 日开始天天改
res/values/ strings.xml、colors.xml、styles.xml、themes.xml 不放文件名当 ID;XML 节点名决定 R 中的字段名
res/drawable/ 位图(PNG/JPEG)、.9.png、Shape、Selector 第 2 日开始大量使用 Shape/Selector
res/mipmap-*dpi/ 应用图标(多分辨率) AS 默认生成,不要手动改文件名
res/menu/ 菜单 XML(Toolbar 用) 第 14 日起
res/anim/ 动画 XML(淡入、旋转、补间) 第 16 日旋转动画
res/xml/ 杂项配置(backup_rules.xml、network_security_config.xml 等) 本课几乎不动

判断资源放哪儿的捷径:

  1. 要在代码里用资源 ID 拿的(如 findViewById、setBackgroundResource) → 放 res/。
  2. 要保留原文件名 / 目录层级当字面路径读的 → 放 assets/。

5. assets/ 与res/raw/ 怎么选

这是初学者最容易混的一组——它们都能塞「原文件」,区别只在访问方式。

维度 res/raw/ assets/
是否进入 R.java ✅ 是,用 R.raw.bg 引用 ❌ 否
文件名是否保留原样 文件名就是 R 里的字段名(如 R.raw.song) 保留原文件名 + 目录结构
访问 API Resources.openRawResource(R.raw.x) AssetManager.open("sub/x.mp3")
适用场景 MediaPlayer 播一段 ogg、铃声;少量固定文件 整个 mp3 目录、HTML 模板、JSON 配置目录

一句话:用「资源 ID」引,放 raw/;用「路径」读,放 assets/。

例:第 17 日做 JSON 模拟网络列表,可以把 songs.json 放 assets/sample/,代码里这样读:

InputStream is = null; try { is = getAssets().open("sample/songs.json"); // …read & parse… } finally { if (is != null) { try { is.close(); } catch (Exception ignored) {} } }

注意 try / catch / finally 里显式关流——本课禁止 try-with-resources。


6. 课程约定的 Java 子包结构

按课程大纲 2.3 节:「能按职责把源码放到 ui / adapter / model / util / db / listener / service 等子包,根包名仍用 edu.cdp.android.dayNN。」

第 1 日就是 MainActivity 一个文件,没必要拆;从第 4 日起按这套约定分包。例如第 14 日音乐项目:

edu.cdp.android.day14/ ├── SongListActivity.java ← 入口(Activity = UI 的根) ├── model/ │ └── SongItem.java ← 数据类 ├── db/ ← (本课第 7 日起才有) ├── util/ │ └── SongScanner.java ← 扫描 / IO 工具 ├── adapter/ │ └── SongAdapter.java ← 继承 BaseAdapter ├── listener/ │ ├── SongItemClickListener.java ← 具名监听器 │ └── ToolbarMenuClickListener.java └── service/ └── (第 15 日加 PlayService)

约定只有三条:

  1. Activity 类放在根包(方便 Manifest 用 .MainActivity 这种短名字引到)。
  2. 具名监听器统一放 listener/(独立类或 Activity 内部具名类;本课前面日子用内部具名类也可以,但归在 listener/ 子包里更整齐)。
  3. 同职责的东西相邻(DAO 放 db/、工具放 util/、业务模型放 model/),不要随手丢在根包。

一句话总结: 根目录管 Gradle;app/src/main/ 里只有清单、Java、资源三件套;资源能进 R 的放 res,要按路径读原文件的放 assets;业务代码按 ui / adapter / model / util / db / listener / service 分子包,根包仍是 edu.cdp.android.dayNN。

转载请注明来源:工程目录结构说明
本文链接地址:https://ai.zhousir.top/?p=436
回复 取消