第一个 Hello World 应用
新建 Empty Views Activity 项目、运行到模拟器、目录结构初探、修改 TextView 文案并构建可安装 APK
学习目标
- 使用 Android Studio 模板新建 Empty Views Activity Java 项目并配置 SDK 版本
- 把应用运行到模拟器并通过 Logcat 查看日志
- 初步认识 app 模块的目录结构(manifest / java / res)
- 修改 activity_main.xml 中 TextView 的文案并重新运行
- 用 Gradle 命令行构建一个 release/debug APK
学习目标
第 1 章我们搞定了环境,本章把环境用起来:从零创建一个 Java 版的 Hello World,让它跑在模拟器上,并理解“一个 Android App 是怎么从源码变成屏幕上的文字”。具体目标:
- 用 Empty Views Activity 模板新建一个 Java 项目并配置
compileSdk 34、minSdk 24; - 通过 Run 把应用安装到模拟器,并在 Logcat 验证进程已启动;
- 初步认识
app/src/main下的三大目录:java/、res/、AndroidManifest.xml; - 修改
activity_main.xml中 TextView 的文案,观察 UI 变化; - 用 Gradle 命令行产出 debug APK 并查看其产物。
新建 Empty Views Activity 项目
1. 模板选择
Android Studio Hedgehog 之后模板被重新组织。我们选用 Empty Views Activity,它生成的是经典 View 体系项目,而非 Jetpack Compose。理由:本教程前半部分用 View + Java 讲解基础,Compose 留到 Part 9。
操作步骤:
- Android Studio 主界面
New Project; - 在 Phone and Tablet 分类下选
Empty Views Activity; - 弹出配置窗口,按下表填写:
| 字段 | 值 | 说明 |
|---|---|---|
| Name | HelloApp | 应用名 |
| Package name | com.example.helloapp | 全小写,至少两段 |
| Save location | D:\projects\HelloApp | 路径不含中文/空格 |
| Language | Java | 本教程主语言 |
| Minimum SDK | API 24 (Android 7.0) | 覆盖 95%+ 设备 |
| Build configuration language | Groovy DSL (build.gradle) | 用 .gradle 而非 .gradle.kts |
| Use legacy android.support libraries | 不勾选 | 用 AndroidX |
- 点击 Finish,等待 Gradle 同步完成(首次 5-15 分钟)。
2. 模板生成的 build.gradle(app 级)
新建完成后,app/build.gradle 长这样(节选):
plugins {
id 'com.android.application'
}
android {
namespace 'com.example.helloapp'
compileSdk 34
defaultConfig {
applicationId "com.example.helloapp"
minSdk 24
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}
注意:
namespace决定生成的R类包名,必须与applicationId同源,但两者不必完全相同;compileSdk与targetSdk都设为 34,minSdk24,对应本教程约定;sourceCompatibility与targetCompatibility都升到 17,与第 1 章的 JDK 17 对齐。
运行到模拟器
1. 选择运行设备
顶部工具栏右侧的下拉框应能自动识别第 1 章创建的 Pixel_7_API_34 AVD。如果没显示,重启 Android Studio 或手动点击 Device Manager → Refresh。
2. 点击 Run
点绿色 ▶ 按钮,Android Studio 会执行:
- Build:调用 Gradle 执行
assembleDebug,编译 Java、处理资源、生成R.java、合并 manifest; - Install:通过
adb install把app-debug.apk安装到模拟器; - Start:发出
am start -n com.example.helloapp/.MainActivity启动主 Activity。
构建过程输出在底部 Build 标签:
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuildConfig UP-TO-DATE
> Task :app:compileDebugJavaWithJavac
> Task :app:processDebugResources
> Task :app:packageDebug
> Task :app:installDebug
Installed on 1 device.
模拟器屏幕出现空白页面,正中央显示 Hello, World!。
3. 用 Logcat 验证进程
底部 Logcat 标签,左侧选设备 Pixel_7_API_34,过滤栏输入 package:com.example.helloapp。能看到类似输出:
2024-01-01 10:00:01.123 1234-1234 ActivityTaskManager I ... START com.example.helloapp/.MainActivity ...
2024-01-01 10:00:01.200 1234-1234 helloapp D ... Loaded apk ...
如果要自己加日志,可以在 MainActivity.java 里写:
package com.example.helloapp;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "HelloApp";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: 应用启动");
}
}
按 Ctrl + F10(Windows)重新 Run,Logcat 过滤 tag:HelloApp 能看到 onCreate: 应用启动。
4. 真机运行(可选)
如果你有真机:
- 手机 → 设置 → 关于手机 → 连续点击 7 次“版本号”启用开发者选项;
- 设置 → 系统 → 开发者选项 → 开启
USB 调试; - 用 USB 连接电脑,弹窗选
传输文件,授权指纹; - Android Studio 顶部下拉框选你的手机型号,再点 Run。
部分国产 ROM(如 MIUI、ColorOS)需要在开发者选项里额外开启
USB 安装与无线调试权限,否则首次安装 APK 会被拦截。
目录结构初探
新建项目后,左侧 Project 视图默认用 Android 模式展示。切到 Project 模式(右上角下拉)能看到真实目录树:
HelloApp/
├── .gradle/ # Gradle 缓存
├── .idea/ # IDE 配置
├── app/
│ ├── build.gradle # 模块级构建脚本
│ ├── proguard-rules.pro # 代码混淆规则
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/com/example/helloapp/
│ │ └── MainActivity.java
│ └── res/
│ ├── drawable/ # 矢量图
│ ├── layout/
│ │ └── activity_main.xml
│ ├── mipmap-anydpi-v26/
│ │ └── ic_launcher.xml # 自适应图标
│ ├── mipmap-hdpi/
│ │ └── ic_launcher.png # 普通图标
│ ├── values/
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ └── xml/
│ ├── backup_rules.xml
│ └── data_extraction_rules.xml
├── build.gradle # 项目级脚本
├── settings.gradle # 模块聚合与仓库
├── gradle.properties # Gradle 与 AndroidX 配置
└── local.properties # 本机 SDK 路径,不入库
1. AndroidManifest.xml
清单文件,向系统声明应用基本信息(包名、版本、组件、权限等)。模板生成的关键节点:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.HelloApp">
<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>
android:exported="true" 自 Android 12 起对带 intent-filter 的入口 Activity 强制要求显式声明,否则安装失败。
2. MainActivity.java
package com.example.helloapp;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
setContentView(R.layout.activity_main) 把 res/layout/activity_main.xml 设为当前界面,框架会自动解析 XML 并实例化 View 树。
3. activity_main.xml
模板生成的布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/main_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, World!"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
注意 tools:context 仅在预览中起作用,编译时被忽略;xmlns:tools 命名空间需要在文件头部声明(IDE 自动补全)。
修改 TextView 文案
1. 直接改 XML
把 android:text="Hello, World!" 改成 "你好,Android!"。按 Ctrl + R10(或点 Run)重新部署,模拟器屏幕文字变化。
2. 推荐做法:用 strings.xml
把硬编码字符串迁到 res/values/strings.xml:
<resources>
<string name="app_name">HelloApp</string>
<string name="main_greeting">你好,Android!</string>
</resources>
布局里改用引用:
<TextView
android:id="@+id/main_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_greeting" />
好处:
- 多语言只需新增
values-zh-rTW/、values-en/等目录即可切换; - 字符串集中管理,复用率高;
- lint 能识别未使用的字符串资源。
3. 在代码里改文案
package com.example.helloapp;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView greeting = findViewById(R.id.main_text);
greeting.setText(getString(R.string.main_greeting));
}
}
findViewById 是经典 View 体系的查控件方式,返回 View,需要强转为具体类型。后续会用 ViewBinding 替代它,避免类型转换风险。
构建 APK
1. Debug APK
最简单:菜单 Build → Build Bundle(s) / APK(s) → Build APK(s)。完成后弹窗点 locate 找到 app/build/outputs/apk/debug/app-debug.apk。
命令行等价做法:
# 在项目根目录执行
.\gradlew.bat :app:assembleDebug
构建产物路径:
app/build/outputs/apk/debug/app-debug.apk
直接拖到运行中的模拟器即可安装。也可以用 adb 安装:
adb install app/build/outputs/apk/debug/app-debug.apk
2. Release APK
release 构建需要签名。最简流程:菜单 Build → Generate Signed Bundle / APK → 选 APK:
- Module 选
app; - Key store path 点
Create new:- Key store path:
D:\keys\helloapp.jks - Password:至少 6 位,例如
123456 - Alias:
helloapp - Validity (years):
25 - 填写姓名、组织、城市、国家等;
- Key store path:
- 选
releaseBuild Variant,勾选V1 (Jar Signature)与V2 (Full APK Signature); - 点 Finish,等待生成
app-release.apk。
不要把
.jks与密码提交到 Git,建议放D:\keys\这种项目外目录,并用proguard-rules.pro、CI 加密变量管理。
3. 命令行 release 构建(签名配置)
在 app/build.gradle 中加签名配置:
android {
signingConfigs {
release {
storeFile file('D:/keys/helloapp.jks')
storePassword '123456'
keyAlias 'helloapp'
keyPassword '123456'
}
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}
实际工程中密码应放
~/.gradle/gradle.properties,不要写死在脚本里:
signingConfigs {
release {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}
执行:
.\gradlew.bat :app:assembleRelease
产物:app/build/outputs/apk/release/app-release.apk。
4. 检查 APK
用 aapt 查看 APK 的应用名、版本、入口:
aapt dump badging app/build/outputs/apk/release/app-release.apk
输出包含:
package: name='com.example.helloapp' versionCode='1' versionName='1.0'
launchable-activity: name='com.example.helloapp.MainActivity'
aapt.exe 位于 $sdkRoot\build-tools\34.0.0\,把该路径加入 PATH 才能直接调用。
常见坑与最佳实践
- 模板选成
Empty Activity(Compose):从 Hedgehog 起Empty Activity默认生成 Compose 项目,Java 项目要选Empty Views Activity。混淆后用ViewBinding时会找不到布局。 R.layout.activity_main报红:通常是 Gradle 同步失败或刚改了 manifest 没同步。点File → Sync Project with Gradle Files,必要时Build → Clean Project再 Rebuild。findViewById返回 null:必须在setContentView之后调用,且R.id.xxx必须真实存在于当前布局 XML 中;用 ViewBinding 可彻底避免此类 NPE。minSdk设置过低导致 lint 报错:本教程统一minSdk 24,如果调用了 API 26+ 的方法(如String.join),需要if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)保护。- release 包崩溃但 debug 不崩:开了
minifyEnabled true后未在proguard-rules.pro保留反射使用的类,导致ClassNotFoundException。对外暴露的 Java Bean、@Entity、@Parcelize等需要-keep。 - 硬编码字符串难做国际化:所有用户可见文字都应放
strings.xml,按values-zh/、values-en/拆分;lint 中HardcodedText警告要全部消除。 - 修改图标没生效:
AndroidManifest.xml的android:icon指向@mipmap/ic_launcher,而ic_launcher.xml(自适应图标)会根据mipmap-anydpi-v26覆盖旧版 PNG,老版本可能显示默认。要确认drawable/ic_launcher_foreground.xml等前置资源存在。 - 构建超时卡
gradle-8.x-all.zip:第一次同步时把对应版本离线包放到~/.gradle/wrapper/dists/gradle-8.x-all/<hash>/下,再次同步会跳过下载。
章节小结
- 用
Empty Views Activity模板新建 Java 项目,compileSdk 34/targetSdk 34/minSdk 24是本教程统一约定; - Run 流程 =
assembleDebug→adb install→am start,可在 Build / Logcat 标签验证; - 项目三大核心:
AndroidManifest.xml声明组件、java/放逻辑、res/放资源,R类把它们桥接起来; - 用户可见文字应放
strings.xml引用,不要硬编码; - Debug APK 用
Build APK(s)一键产出,Release APK 需要签名(.jks+ signingConfigs)。
下一章预告
第 3 章我们会深入项目结构:逐行剖析 AndroidManifest.xml、res 目录下的 layout/values/drawable/mipmap、build.gradle、settings.gradle、gradle.properties、签名配置与 proguard-rules.pro,让你看懂“模板都帮我们配了什么”。