
第一次在 Android Studio 里点下那个 Run 按钮看着模拟器慢慢开机、界面亮起来那种感觉和写完第一行 Hello World 差不多。但真要说实话从下载安装包到那个界面成功蹦出来中间隔着的东西比想象中多Android 环境、SDK 组件、Gradle 构建、项目目录结构每一层都能把人卡住半天。移动应用开发就是这样Android 项目的创建看着只是几个向导页面实际上它把后面几个月要打交道的东西全埋进去了。这篇内容我想按真实的操作顺序把创建第一个 Android 项目从头到尾捋一遍包括每一处参数为什么这么选、目录为什么这么放、报错为什么会冒出来。不管你是刚接触安卓开发的在校学生还是从别的语言转过来想碰移动端的老手甚至是准备拿一个完整项目去参加移动应用设计与开发类竞赛的选手这套流程和踩坑记录应该都能直接用上。1. 环境这一步没走稳后面全是坑1.1 为什么首选 Android Studio 而不是别的方案很多人一开始会纠结写 Android 到底是装 Android Studio还是用 VS Code 加插件或者干脆用命令行。我的建议很直接第一个 Android 项目就用 Android Studio别折腾别的。原因不在于它有多好用而在于它是官方整条工具链的总入口——SDK 管理、模拟器、布局预览、性能分析、签名打包全在这一套里。用 VS Code 加插件当然能写代码但你得自己装 SDK、自己配构建命令行、自己解决 Gradle 同步问题等于把 Android Studio 帮你兜的那些事全接过来自己扛。新手阶段最怕的不是代码写不出来而是环境问题查不出来一个报错搜半天发现是 SDK 版本不对这种消耗非常打击信心。Android Studio 还有一个被低估的好处它的布局编辑器可以实时预览界面改一个属性右边就变一下。对刚学 Android 布局的人来讲这个即时反馈比看文档快十倍。所以第一阶段的策略很简单先把官方工具用熟等你知道每一步背后发生了什么再去换轻量方案也不迟。注意Android Studio 版本尽量选较新的稳定版不要用 Beta 或 Canary 通道的版本练手。预览版会有一些不稳定的行为新手很难判断是代码问题还是工具问题。1.2 安装包下载与安装位置的取舍安装包下载这一步本身不难官网直接下对应系统的版本就行。真正值得说的是装在哪里、装完之后那个 SDK 放哪里。Windows 上默认会装到系统盘的用户目录下macOS 上是 Applications 加用户目录。这里面有两个空间大户一个是 Android Studio 本体几个 G另一个是 SDK 和模拟器镜像装几个系统镜像之后轻松超过二十个 G。如果你的系统盘空间紧张我的做法是把 SDK 路径单独指到一个空间大的盘。在安装向导里会有一页专门问 SDK 装哪里这时候改掉就行。装完之后如果发现忘了改也可以在设置里的 SDK 路径选项里重新指定它会自动迁移或者提示你手动搬。模拟器的镜像文件同理可以在模拟器管理里看到每个镜像占用的空间不用的系统版本删掉能省出不少地方。另一个细节是 JDK。Android Studio 现在自带了一个 JetBrains Runtime也就是内置的 JDK不需要你单独去装 Java。AGP 8.x 这一代构建插件要求 JDK 17而自带的就是这个版本所以你完全不用管。早年那些开发安卓要先装 JDK 再配环境变量的教程现在基本不用听了照着做反而容易因为版本冲突把环境搞乱。1.3 SDK 组件清单哪些必装哪些可以往后放Android Studio 装完之后第一次打开会引导你下载 SDK。这里有个概念要先搞清楚SDK 不是一个整体而是一堆组件的集合主要包括平台版本、构建工具、平台工具和模拟器相关的东西。平台版本就是所谓 Android 14、Android 15 对应的 SDK Platform每个版本一个包。构建工具是 Build-Tools负责把代码编译打包成 apk。平台工具是 Platform-Tools里面最重要的就是 adb后面装应用、看日志、连真机全靠它。这三个是核心必须装。至于具体装哪个平台版本我的建议是装一个你打算编译目标用的高版本再装一个你最低支持的低版本。比如你把编译目标定在 API 35最低支持定在 API 24那至少把 35 装上24 那个包有时候为了兼容性检查也会用到。构建工具不用手动一个个挑Gradle 在同步的时候会按需下载但第一次同步会慢如果你提前在 SDK 管理里装好对应版本能省掉一次等待。模拟器镜像属于可选项。你如果有真机完全可以先不装模拟器直接用手机调试速度快得多。真要装优先装一个 x86_64 或者 arm64 的镜像别贪多一个跑通就够。1.4 环境阶段最容易翻车的四个地方我把这些年遇到频率最高的几个环境问题列一下基本都集中在第一次配置阶段。第一个是路径里有中文或者空格。SDK 路径、项目路径、Gradle 缓存路径这三处只要有一处带中文就可能出现各种奇怪的编译报错比如找不到资源、AAPT 报错之类。最稳妥的做法是全程用纯英文路径项目建在一个专门的英文目录下。第二个是杀毒软件或者系统防护拦截构建过程。Gradle 构建的时候会大量读写临时文件、启动子进程有些安全软件会把它当成可疑行为直接导致构建中断或者速度奇慢。如果构建总是莫名其妙失败可以先把项目目录和 SDK 目录加进白名单。第三个是模拟器和硬件的兼容问题。较老的电脑如果没有开启虚拟化支持模拟器会跑不起来或者卡到没法用。这个要在 BIOS 里开虚拟化或者干脆放弃模拟器用真机。第四个是磁盘空间。这个前面提过但要强调一次Gradle 缓存加上 SDK 加上模拟器一百个 G 不算夸张。空间不足的时候构建失败报的错往往和空间不足毫无关系你会以为是代码问题其实是磁盘满了。2. 创建第一个 Android 项目向导里每一步都在做什么决定2.1 模板选择的门道打开 Android Studio点 New Project会看到一个模板列表。上面有 Empty Activity、Empty Views Activity、Basic Views Activity、Bottom Navigation Activity、Empty Compose Activity 等等。新手看到这个列表容易犯选择困难其实决策逻辑很简单先确认你要用 XML 布局还是 Compose。Compose 是声明式 UI写起来像写代码里嵌 UI比较新XML 布局是传统方式界面和逻辑分离资料量巨大。就第一个项目而言我更推荐用 Empty Views Activity也就是传统的 XML 布局模板。原因不是它更好而是你在网上搜到的绝大多数教程、问答、示例都是基于 XML 的遇到问题更容易找到答案。等把基础逻辑跑通之后再转 Compose 会很顺。模板本质上只是帮你生成了一套起步代码和目录结构选哪个都不影响你后面能做什么。真正需要注意的是模板名字里带 Views 的和不带 Views 的差别前者是 XML 布局后者通常是 Compose。这个细节很多人第一次会看漏建完项目发现代码长得完全不一样还以为自己下错了版本。2.2 包名、语言、最低支持版本怎么定向导第二页有几个关键参数逐个说一下。项目名Name随便起但建议用英文别用中文它会参与生成一些文件名。包名Package name是应用在系统里的唯一身份格式是反向域名比如 com.example.myfirstapp。这个包名一旦确定后面上架、签名、更新都要保持一致改起来比较麻烦所以第一次就按公司或个人域名 项目名的规范来写别用默认的 com.example 直接上架因为 Google Play 不允许 com.example 开头的包名。语言选择 Kotlin 还是 Java。现在新建项目默认是 Kotlin我建议直接用 Kotlin。不是说 Java 不能写而是官方文档、示例代码、新出的库默认都优先 Kotlin用 Kotlin 的学习阻力更小。Java 也不是白学两者可以互调看懂 Java 代码对读老项目很有帮助。最低支持版本Minimum SDK是这一页最需要动脑的地方。它决定了你的应用能装到多老的手机上选得越低覆盖设备越多但你能用的新 API 越少。Android Studio 会给你一个参考百分比比如选 API 24 的时候会显示覆盖了绝大多数在用设备。我第一次建项目时选的是 API 24用到现在也没觉得有什么不便性价比很高。构建配置语言Build configuration language选 Kotlin DSL 还是 Groovy。新版默认是 Kotlin DSL也就是 .kts 结尾的文件。两者语法有差别但概念一样如果你搜到的教程是 Groovy 写法对照着看也能明白。参数建议值理由包名com.你的域名.项目名唯一身份上架后不能随意改语言Kotlin官方默认资料优先适配最低支持版本API 24 左右覆盖广成本低构建语言Kotlin DSL新版默认长期趋势编译目标较新的 API 版本满足商店的上架要求2.3 首次 Gradle 同步到底在干什么点完 FinishAndroid Studio 会开始同步底下一行进度条有时候转很久。这一步实际上是在做几件事读取构建脚本、解析依赖坐标、下载缺失的库和插件、生成一些编译用的中间文件、建立索引。第一次同步慢是正常的因为它要从远程仓库拉一堆东西下来包括 Gradle 本体、Android Gradle Plugin、各种依赖库。国内网络环境下这个过程可能特别慢甚至超时。解决办法是配置镜像仓库把依赖解析指向国内的镜像地址速度会有明显提升。这不是什么高深技巧就是在 settings 文件里把仓库地址换一下。下面是一段典型的仓库配置放在settings.gradle的依赖管理块里dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { maven { url https://maven.aliyun.com/repository/public } maven { url https://maven.aliyun.com/repository/google } maven { url https://maven.aliyun.com/repository/gradle-plugin } google() mavenCentral() } }镜像地址放在前面官方仓库兜底这样既快又不容易缺包。改完之后点同步通常能明显感觉到差别。注意改仓库配置时不要只保留镜像、删掉官方仓库。镜像有时候会缺某个比较新的包留一个官方地址兜底能避免找不到依赖这种莫名其妙的错误。同步过程中如果右下角弹出提示说 Gradle 版本或者插件版本不匹配别急着点升级。先看看提示里说的问题是什么很多时候只是版本号对应关系的问题直接按它推荐的处理即可。乱升级反而容易把一套能跑的配置搞崩。2.4 项目工程视图怎么切换才看得懂同步完成之后左侧会显示项目结构。默认可能是 Android 视图这个视图做了简化把真正参与编译的东西挑出来展示看起来清爽但它和磁盘上的真实目录结构并不完全一致。如果你要理解项目结构建议切成 Project 视图这时候看到的就是磁盘上真实的文件夹层级。很多人搜索资料的时候看到别人说打开 app/src/main结果在 Android 视图里怎么也对不上就是因为视图不一样。两个视图各有用途Android 视图适合日常开发找资源文件、找代码方便Project 视图适合理解结构、处理配置文件、解决构建问题。我自己的习惯是平时用 Android 视图一旦遇到构建报错就切到 Project 视图看真实路径。3. 项目目录拆解每个文件夹都不能白放3.1 app 模块与两级 build.gradle新建出来的项目最外层有一个 app 文件夹这就是你的主模块。一个 Android 项目可以包含多个模块比如后续你可能加一个 library 模块放公共代码但第一个项目就一个 app 模块够用。构建脚本分两级。最外层那个build.gradle是项目级的一般只声明插件版本不写具体依赖。app 目录里那个build.gradle是模块级的应用的编译版本、最低版本、依赖库全在这里配。很多人搞不清该改哪个记住一句话跟具体应用有关的配置改模块级跟整个项目构建方式有关的改项目级。模块级脚本里有两块最常动。一块是android { }里面写compileSdk、minSdk、targetSdk、版本号这些。另一块是dependencies { }你后面要加的网络库、图片库、数据库全都往这里加。加完依赖必须重新同步一次否则代码里 import 不进来。android { namespace com.example.myfirstapp compileSdk 35 defaultConfig { applicationId com.example.myfirstapp minSdk 24 targetSdk 35 versionCode 1 versionName 1.0 } }这里applicationId和namespace看起来像重复的其实职责不同applicationId是装在手机上的那个唯一标识namespace是代码里生成 R 类用的包名前缀。多数情况下两者一样但如果你想做多渠道打包可能需要让applicationId有后缀差异这时候就能看出区别了。3.2 AndroidManifest.xml应用的户口本清单文件在app/src/main/AndroidManifest.xml它是系统认识你应用的第一份资料。里面声明了应用用到了哪些权限、包含哪些页面Activity、应用的图标和名称从哪来、支持哪些屏幕方向等等。新建项目之后你打开这个文件会看到 application 标签里有一个 activity 标签里面写着 MainActivity并且带一个 intent-filter配置了 MAIN 和 LAUNCHER。这两个标记的意思是这是应用的入口页面点图标进来先打开它。如果你以后新建了别的 Activity忘记在这里注册运行的时候就会直接崩溃报 ActivityNotFoundException。这是新手非常高频的一个坑。权限也在这里声明。比如后面你要联网就得加一条网络权限要读相册就得加对应的存储权限。有一个容易混淆的点从较新的 Android 版本开始部分权限需要同时在代码里动态申请光在清单里写是不够的。清单声明是我打算用运行时申请是用户同意我用两步都得有。3.3 res 资源目录的组织逻辑res目录是资源的大本营里面按类型分了若干子目录。layout放布局文件一个界面一个 xmldrawable放图片和矢量图mipmap放应用图标values放颜色、字符串、主题这些常量xml放一些配置类文件。这套分类不是随便定的是为了让系统能按不同设备条件自动选择合适的资源。举个实际的例子你在values里定义一句字符串然后想在中文和英文下显示不同内容只需要再建一个values-en目录放英文的版本系统会根据系统语言自动挑。图片也一样不同分辨率可以放drawable-hdpi、drawable-xhdpi之类的目录。这就是 Android 资源系统的核心思路同类资源多个版本系统按条件匹配。values/strings.xml值得单独说一句。新手习惯把界面上的文字直接写在布局文件里比如android:text确定。这能跑但不规范。正确做法是把文字放进 strings.xml布局里用string/xxx引用。好处一是好改二是方便多语言三是减少重复。一开始可能觉得麻烦但养成习惯之后会省很多事。3.4 常用目录速查表把上面这些整理成一张表找东西的时候直接对着看。路径作用什么时候会动它app/src/main/javaKotlin 或 Java 源码写业务逻辑app/src/main/res/layout界面布局文件改界面app/src/main/res/values字符串、颜色、主题加文字、改配色app/src/main/res/drawable图片与图形资源加图标、背景app/src/main/res/mipmap应用启动图标换 Logoapp/src/main/AndroidManifest.xml权限与组件声明加页面、加权限app/build.gradle模块构建配置加依赖、改版本gradle/wrapperGradle 版本锁定升级构建工具有一类目录我要单独提醒就是app/build这个目录它是构建产物里面的东西全是自动生成的不要手动去改改了也会被下一次构建覆盖。有时候构建出问题删掉这个目录重新构建是一种常见的清理手段。4. 让第一个界面真的动起来4.1 用 XML 搭一个输入加按钮的界面光看目录不动手理解不会深。我们做一个小功能一个输入框、一个按钮、一个结果文本输入名字点按钮显示问候。这个例子小但把布局、找控件、绑事件、改内容这条完整链路走了一遍。打开res/layout/activity_main.xml把默认的内容换成一个垂直的线性布局?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical android:padding24dp android:gravitycenter EditText android:idid/etName android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入你的名字 android:inputTypetext / Button android:idid/btnGreet android:layout_widthmatch_parent android:layout_heightwrap_content android:layout_marginTop16dp android:text打招呼 / TextView android:idid/tvResult android:layout_widthmatch_parent android:layout_heightwrap_content android:layout_marginTop24dp android:textSize18sp android:gravitycenter / /LinearLayout这里面几个点值得说。match_parent表示占满父容器宽度wrap_content表示按内容自适应高度这两个是 Android 布局里出现频率最高的取值。dp是尺寸单位sp是字体单位——字体用 sp 是因为它会跟随用户在系统里设置的字体大小缩放用 dp 就失去了这个能力这是个很容易忽略的细节。android:idid/etName这一行给控件起了个标识后面的代码靠这个 id 找到它。id里的加号表示如果这个 id 还不存在就创建它第一次写某个 id 时用加号后面引用时不加。这个规则一开始容易忘忘了加号会报找不到符号。4.2 在 Activity 里绑定控件与响应事件布局搭好了接下来在MainActivity里写逻辑。class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val etName findViewByIdEditText(R.id.etName) val btnGreet findViewByIdButton(R.id.btnGreet) val tvResult findViewByIdTextView(R.id.tvResult) btnGreet.setOnClickListener { val name etName.text.toString().trim() tvResult.text if (name.isEmpty()) { 名字还没填呢 } else { 你好$name } } } }setContentView这行是把布局文件挂到当前页面上必须写在最前面否则findViewById找不到控件会返回空。findViewById按 id 从布局里把控件对象取出来泛型里的类型要和实际控件对上对不上就是类型转换异常。setOnClickListener给按钮绑了一个点击回调里面就是点击后要执行的事。etName.text拿到的是可编辑文本对象.toString()转成字符串.trim()去掉首尾空格——这一步很重要用户手滑打个空格你的判空逻辑就失效了。tvResult.text ...是修改文本内容注意这里没有调用什么刷新方法赋值直接生效。这是 Android UI 的一个特点但同时也带来一个限制只能在主线程更新界面子线程里直接改会抛异常。后面做网络请求的时候这一点会变得非常关键。4.3 跑到模拟器和真机上看看代码写完点运行按钮如果有模拟器就选模拟器没有就插真机。真机需要先在开发者选项里打开 USB 调试连上之后在 Android Studio 的设备列表里应该能看到设备名。真机调试的体验比模拟器好很多启动快、操作跟手、还能测真实的触摸和性能。插上之后如果列表里没有通常是三个原因数据线只能充电不能传数据、手机没授权这台电脑、驱动没装好。前两个最常见换根线、在手机上点一下允许调试基本就能解决。运行起来之后在输入框打字点按钮看结果文本有没有变。第一次成功跑通这个小功能比看十篇教程都管用因为整条链路你自己走过一遍了。4.4 用 ViewBinding 替代 findViewById上面的写法能用但控件一多就很啰嗦。每个控件都要写一行findViewById还得手动指定类型写错了运行时才报错。更好的做法是开启 ViewBinding。在模块级构建脚本的android { }里加一行buildFeatures { viewBinding true }同步之后系统会为每个布局文件生成一个绑定类文件名是布局名转成驼峰再加 Binding。activity_main.xml会生成ActivityMainBinding。使用方式变成class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.btnGreet.setOnClickListener { val name binding.etName.text.toString().trim() binding.tvResult.text if (name.isEmpty()) 名字还没填呢 else 你好$name } } }好处有三个不用手写 id 查找编译器帮你检查控件类型布局里的 id 变了代码会直接报编译错误而不是运行时崩溃。中小型项目里 ViewBinding 基本是标配早点用上能少踩不少空指针的坑。注意开了 ViewBinding 之后原来手写的 findViewById 代码不会自动失效但新代码建议统一用绑定类混着用容易记不清哪个控件是哪种方式拿的。5. 常见问题与排查实录5.1 Gradle 同步失败与依赖下载慢同步失败是最常见的问题报错信息通常很长但真正有用的往往就最后几行。最常见的两类一类是网络问题导致的下载超时一类是版本不匹配。网络问题按前面说的配镜像基本能解决。如果配了镜像还是失败检查一下公司或学校的网络是不是做了限制换个网络环境试试。还有一种是 Gradle 自身的分发包下载慢这个可以在 wrapper 配置里指定分发包的下载地址换一个速度好的源。版本不匹配的表现通常是提示某个插件需要更高的 Gradle 版本或者某个依赖需要更高版本的编译工具。这时候看提示里的具体要求把对应版本号改一下再同步。不要一次性改好几个地方一次改一处同步一次这样出问题能定位。还有一种比较隐蔽的情况同步看起来成功了但代码里引用某个库的类还是标红。这通常是缓存问题可以试试清理并重新同步或者删除项目里的构建缓存目录重新来一次。这种看起来没问题但实际有问题的情况用重启大法往往真能解决。5.2 真机识别不了、安装被拒绝真机连不上前面说了三个原因再补充一个有些定制系统需要在开发者选项里额外打开USB 安装之类的开关否则能识别设备但装不上应用。安装被拒绝的提示通常是应用未安装或者安装包解析失败前者多数是签名或者已存在同包名不同签名的应用后者通常是安装包损坏或者最低版本不匹配。同一个包名但签名不同的应用直接覆盖安装会失败需要先卸载旧版本。这个在多人协作或者换电脑开发的时候特别容易遇到因为每台电脑的调试签名不一样。解决办法是让团队统一用同一份调试签名或者干脆每次都卸载重装。还有一个和安装相关的小细节应用装到手机之后如果你改了代码重新运行Android Studio 会自动做增量安装速度快。但如果改了权限声明、改了清单文件里的重要配置有时候需要卸载重装才生效。遇到代码明明改了但行为没变的情况先试卸载重装。5.3 日志、断点与调试效率调试手段里日志是最常用的。Android 里用 Log 类输出有 Verbose、Debug、Info、Warn、Error 几个级别。开发阶段一般用 Debug发布版本里尽量别留太多日志输出。在日志窗口里日志量非常大系统进程、其他应用的输出都混在一起。要过滤自己的日志可以在过滤器里按标签或者按包名筛选。给每个类定义一个固定的日志标签是个好习惯找起来方便。private const val TAG MainActivity Log.d(TAG, 按钮被点击输入内容为 $name)断点调试比日志更直接。在代码行号旁边点一下就能加断点运行时程序会停在那里这时候可以查看所有变量的当前值、单步执行、进入方法内部。排查逻辑错误的时候断点比满屏打印日志高效得多尤其是那种条件明明满足但没进分支的问题看一眼变量值就明白了。注意断点调试时如果程序卡住不动先确认是不是停在了断点上而不是卡死了。新手有时候会以为是程序崩溃其实只是断点拦住了点继续执行就行。日志窗口里还可以看崩溃堆栈。应用崩溃时堆栈信息会打出来最上面的几行通常就是出问题的地方。别被长长的堆栈吓到重点看第一个Caused by后面跟的内容那里往往就是根因。5.4 问题速查表把上面这些整理成一张表遇到问题先对着看。现象常见原因处理方式同步一直转圈依赖下载慢配置镜像仓库提示版本不匹配插件与 Gradle 版本不对应按提示改版本号代码引用标红缓存未刷新清理并重新同步设备列表为空线材、授权、驱动换线、点允许调试安装失败签名冲突或版本不符卸载旧版再装运行直接闪退Activity 未在清单注册补注册声明界面改了没生效增量构建缓存卸载重装或清理构建找不到控件崩溃布局 id 写错或未 setContentView核对 id 与调用顺序这张表只是起步真正的经验是靠一次次解决具体问题积累出来的。每个报错都值得读一遍完整信息不要看到红的就直接搜先自己判断一下错误类型长期下来排查速度会快很多。6. 我在这条路上踩出来的几条经验第一个项目跑通之后回头看那些卡住我的问题其实绝大多数都不难难的是一开始不知道该看哪里。我的建议是在创建项目时就把版本参数选得保守一点最低支持版本别贪新依赖库别一上来就加一大堆项目越干净出问题的面越小。等第一个能跑的应用稳定了再去加网络、加数据库、加图片加载一次加一样加完跑一遍这样出了问题你能立刻知道是哪一步引入的。还有就是别怕删掉重建。新手经常犯的一个错是环境乱了之后硬要在一堆报错里修修到后面自己都不知道改了什么。其实与其花两小时修复一个乱掉的项目不如花十分钟重新建一个干净的项目把有用的代码复制过去。这不是逃避这是效率。最后说一个我觉得最有价值的习惯每解决一个报错把现象、原因、处理方式记在一个文档里。不用写得多正式几行字就够。Android 这个领域报错类型高度重复你今天踩的坑两周后很可能原样再踩一次。这份自己写的排查笔记比任何教程都更贴合你实际会遇到的场景用久了就是你的私人速查手册。