android-native-dev
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese1. Project Scenario Assessment
1. 项目场景评估
Before starting development, assess the current project state:
| Scenario | Characteristics | Approach |
|---|---|---|
| Empty Directory | No files present | Full initialization required, including Gradle Wrapper |
| Has Gradle Wrapper | | Use |
| Android Studio Project | Complete project structure, may lack wrapper | Check wrapper, run |
| Incomplete Project | Partial files present | Check missing files, complete configuration |
Key Principles:
- Before writing business logic, ensure succeeds
./gradlew assembleDebug - If is missing, create it first and configure AndroidX
gradle.properties
开始开发前,请先评估当前项目状态:
| 场景 | 特征 | 处理方式 |
|---|---|---|
| 空目录 | 无任何文件 | 需要完成完整初始化,包括Gradle Wrapper |
| 已包含Gradle Wrapper | 存在 | 直接使用 |
| Android Studio项目 | 完整项目结构,可能缺少Wrapper | 检查Wrapper,若缺失则运行 |
| 不完整项目 | 仅存在部分文件 | 检查缺失文件,补全配置 |
核心原则:
- 编写业务逻辑前,确保执行成功
./gradlew assembleDebug - 若缺失,请先创建并配置AndroidX
gradle.properties
1.1 Required Files Checklist
1.1 必备文件清单
MyApp/
├── gradle.properties # Configure AndroidX and other settings
├── settings.gradle.kts
├── build.gradle.kts # Root level
├── gradle/wrapper/
│ └── gradle-wrapper.properties
├── app/
│ ├── build.gradle.kts # Module level
│ └── src/main/
│ ├── AndroidManifest.xml
│ ├── java/com/example/myapp/
│ │ └── MainActivity.kt
│ └── res/
│ ├── values/
│ │ ├── strings.xml
│ │ ├── colors.xml
│ │ └── themes.xml
│ └── mipmap-*/ # App iconsMyApp/
├── gradle.properties # Configure AndroidX and other settings
├── settings.gradle.kts
├── build.gradle.kts # Root level
├── gradle/wrapper/
│ └── gradle-wrapper.properties
├── app/
│ ├── build.gradle.kts # Module level
│ └── src/main/
│ ├── AndroidManifest.xml
│ ├── java/com/example/myapp/
│ │ └── MainActivity.kt
│ └── res/
│ ├── values/
│ │ ├── strings.xml
│ │ ├── colors.xml
│ │ └── themes.xml
│ └── mipmap-*/ # App icons2. Project Configuration
2. 项目配置
2.1 gradle.properties
2.1 gradle.properties
properties
undefinedproperties
undefinedRequired configuration
Required configuration
android.useAndroidX=true
android.enableJetifier=true
android.useAndroidX=true
android.enableJetifier=true
Build optimization
Build optimization
org.gradle.parallel=true
kotlin.code.style=official
org.gradle.parallel=true
kotlin.code.style=official
JVM memory settings (adjust based on project size)
JVM memory settings (adjust based on project size)
Small projects: 2048m, Medium: 4096m, Large: 8192m+
Small projects: 2048m, Medium: 4096m, Large: 8192m+
org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
> **Note**: If you encounter `OutOfMemoryError` during build, increase `-Xmx` value. Large projects with many dependencies may require 8GB or more.
> **注意**:如果构建过程中遇到`OutOfMemoryError`,请增大`-Xmx`的值。包含大量依赖的大型项目可能需要8GB或更多内存。2.2 Dependency Declaration Standards
2.2 依赖声明规范
kotlin
dependencies {
// Use BOM to manage Compose versions
implementation(platform("androidx.compose:compose-bom:2024.02.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
// Activity & ViewModel
implementation("androidx.activity:activity-compose:1.8.2")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
}kotlin
dependencies {
// Use BOM to manage Compose versions
implementation(platform("androidx.compose:compose-bom:2024.02.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
// Activity & ViewModel
implementation("androidx.activity:activity-compose:1.8.2")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
}2.3 Build Variants & Product Flavors
2.3 构建变体与产品风味
Product Flavors allow you to create different versions of your app (e.g., free/paid, dev/staging/prod).
Configuration in app/build.gradle.kts:
kotlin
android {
// Define flavor dimensions
flavorDimensions += "environment"
productFlavors {
create("dev") {
dimension = "environment"
applicationIdSuffix = ".dev"
versionNameSuffix = "-dev"
// Different config values per flavor
buildConfigField("String", "API_BASE_URL", "\"https://dev-api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
// Different resources
resValue("string", "app_name", "MyApp Dev")
}
create("staging") {
dimension = "environment"
applicationIdSuffix = ".staging"
versionNameSuffix = "-staging"
buildConfigField("String", "API_BASE_URL", "\"https://staging-api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
resValue("string", "app_name", "MyApp Staging")
}
create("prod") {
dimension = "environment"
// No suffix for production
buildConfigField("String", "API_BASE_URL", "\"https://api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "false")
resValue("string", "app_name", "MyApp")
}
}
buildTypes {
debug {
isDebuggable = true
isMinifyEnabled = false
}
release {
isDebuggable = false
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}Build Variant Naming: → e.g., ,
{flavor}{BuildType}devDebugprodReleaseGradle Build Commands:
bash
undefined产品风味(Product Flavors)允许你创建应用的不同版本(例如免费/付费版、开发/预发布/生产环境版)。
在app/build.gradle.kts中配置:
kotlin
android {
// Define flavor dimensions
flavorDimensions += "environment"
productFlavors {
create("dev") {
dimension = "environment"
applicationIdSuffix = ".dev"
versionNameSuffix = "-dev"
// Different config values per flavor
buildConfigField("String", "API_BASE_URL", "\"https://dev-api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
// Different resources
resValue("string", "app_name", "MyApp Dev")
}
create("staging") {
dimension = "environment"
applicationIdSuffix = ".staging"
versionNameSuffix = "-staging"
buildConfigField("String", "API_BASE_URL", "\"https://staging-api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
resValue("string", "app_name", "MyApp Staging")
}
create("prod") {
dimension = "environment"
// No suffix for production
buildConfigField("String", "API_BASE_URL", "\"https://api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "false")
resValue("string", "app_name", "MyApp")
}
}
buildTypes {
debug {
isDebuggable = true
isMinifyEnabled = false
}
release {
isDebuggable = false
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}构建变体命名规则: → 例如 ,
{flavor}{BuildType}devDebugprodReleaseGradle构建命令:
bash
undefinedList all available build variants
List all available build variants
./gradlew tasks --group="build"
./gradlew tasks --group="build"
Build specific variant (flavor + buildType)
Build specific variant (flavor + buildType)
./gradlew assembleDevDebug # Dev flavor, Debug build
./gradlew assembleStagingDebug # Staging flavor, Debug build
./gradlew assembleProdRelease # Prod flavor, Release build
./gradlew assembleDevDebug # Dev flavor, Debug build
./gradlew assembleStagingDebug # Staging flavor, Debug build
./gradlew assembleProdRelease # Prod flavor, Release build
Build all variants of a specific flavor
Build all variants of a specific flavor
./gradlew assembleDev # All Dev variants (debug + release)
./gradlew assembleProd # All Prod variants
./gradlew assembleDev # All Dev variants (debug + release)
./gradlew assembleProd # All Prod variants
Build all variants of a specific build type
Build all variants of a specific build type
./gradlew assembleDebug # All flavors, Debug build
./gradlew assembleRelease # All flavors, Release build
./gradlew assembleDebug # All flavors, Debug build
./gradlew assembleRelease # All flavors, Release build
Install specific variant to device
Install specific variant to device
./gradlew installDevDebug
./gradlew installProdRelease
./gradlew installDevDebug
./gradlew installProdRelease
Build and install in one command
Build and install in one command
./gradlew installDevDebug && adb shell am start -n com.example.myapp.dev/.MainActivity
**Access BuildConfig in Code**:
> **Note**: Starting from AGP 8.0, `BuildConfig` is no longer generated by default. You must explicitly enable it in your `build.gradle.kts`:
> ```kotlin
> android {
> buildFeatures {
> buildConfig = true
> }
> }
> ```
```kotlin
// Use build config values in your code
val apiUrl = BuildConfig.API_BASE_URL
val isLoggingEnabled = BuildConfig.ENABLE_LOGGING
if (BuildConfig.DEBUG) {
// Debug-only code
}Flavor-Specific Source Sets:
app/src/
├── main/ # Shared code for all flavors
├── dev/ # Dev-only code and resources
│ ├── java/
│ └── res/
├── staging/ # Staging-only code and resources
├── prod/ # Prod-only code and resources
├── debug/ # Debug build type code
└── release/ # Release build type codeMultiple Flavor Dimensions (e.g., environment + tier):
kotlin
android {
flavorDimensions += listOf("environment", "tier")
productFlavors {
create("dev") { dimension = "environment" }
create("prod") { dimension = "environment" }
create("free") { dimension = "tier" }
create("paid") { dimension = "tier" }
}
}
// Results in: devFreeDebug, devPaidDebug, prodFreeRelease, etc../gradlew installDevDebug && adb shell am start -n com.example.myapp.dev/.MainActivity
**在代码中访问BuildConfig**:
> **注意**: 从AGP 8.0开始,默认不再生成`BuildConfig`。你必须在`build.gradle.kts`中显式启用它:
> ```kotlin
> android {
> buildFeatures {
> buildConfig = true
> }
> }
> ```
```kotlin
// Use build config values in your code
val apiUrl = BuildConfig.API_BASE_URL
val isLoggingEnabled = BuildConfig.ENABLE_LOGGING
if (BuildConfig.DEBUG) {
// Debug-only code
}风味专属源码集:
app/src/
├── main/ # Shared code for all flavors
├── dev/ # Dev-only code and resources
│ ├── java/
│ └── res/
├── staging/ # Staging-only code and resources
├── prod/ # Prod-only code and resources
├── debug/ # Debug build type code
└── release/ # Release build type code多风味维度(例如环境 + 层级):
kotlin
android {
flavorDimensions += listOf("environment", "tier")
productFlavors {
create("dev") { dimension = "environment" }
create("prod") { dimension = "environment" }
create("free") { dimension = "tier" }
create("paid") { dimension = "tier" }
}
}
// Results in: devFreeDebug, devPaidDebug, prodFreeRelease, etc.3. Kotlin Development Standards
3. Kotlin开发规范
3.1 Naming Conventions
3.1 命名规范
| Type | Convention | Example |
|---|---|---|
| Class/Interface | PascalCase | |
| Function/Variable | camelCase | |
| Constant | SCREAMING_SNAKE | |
| Package | lowercase | |
| Composable | PascalCase | |
| 类型 | 规范 | 示例 |
|---|---|---|
| 类/接口 | 大驼峰式(PascalCase) | |
| 函数/变量 | 小驼峰式(camelCase) | |
| 常量 | 大写蛇形式(SCREAMING_SNAKE) | |
| 包名 | 全小写 | |
| 可组合函数 | 大驼峰式(PascalCase) | |
3.2 Code Standards (Important)
3.2 代码规范(重点)
Null Safety:
kotlin
// ❌ Avoid: Non-null assertion !! (may crash)
val name = user!!.name
// ✅ Recommended: Safe call + default value
val name = user?.name ?: "Unknown"
// ✅ Recommended: let handling
user?.let { processUser(it) }Exception Handling:
kotlin
// ❌ Avoid: Random try-catch in business layer swallowing exceptions
fun loadData() {
try {
val data = api.fetch()
} catch (e: Exception) {
// Swallowing exception, hard to debug
}
}
// ✅ Recommended: Let exceptions propagate, handle at appropriate layer
suspend fun loadData(): Result<Data> {
return try {
Result.success(api.fetch())
} catch (e: Exception) {
Result.failure(e) // Wrap and return, let caller decide handling
}
}
// ✅ Recommended: Unified handling in ViewModel
viewModelScope.launch {
runCatching { repository.loadData() }
.onSuccess { _uiState.value = UiState.Success(it) }
.onFailure { _uiState.value = UiState.Error(it.message) }
}空安全:
kotlin
// ❌ Avoid: Non-null assertion !! (may crash)
val name = user!!.name
// ✅ Recommended: Safe call + default value
val name = user?.name ?: "Unknown"
// ✅ Recommended: let handling
user?.let { processUser(it) }异常处理:
kotlin
// ❌ Avoid: Random try-catch in business layer swallowing exceptions
fun loadData() {
try {
val data = api.fetch()
} catch (e: Exception) {
// Swallowing exception, hard to debug
}
}
// ✅ Recommended: Let exceptions propagate, handle at appropriate layer
suspend fun loadData(): Result<Data> {
return try {
Result.success(api.fetch())
} catch (e: Exception) {
Result.failure(e) // Wrap and return, let caller decide handling
}
}
// ✅ Recommended: Unified handling in ViewModel
viewModelScope.launch {
runCatching { repository.loadData() }
.onSuccess { _uiState.value = UiState.Success(it) }
.onFailure { _uiState.value = UiState.Error(it.message) }
}3.3 Threading & Coroutines (Critical)
3.3 线程与协程(关键)
Thread Selection Principles:
| Operation Type | Thread | Description |
|---|---|---|
| UI Updates | | Update View, State, LiveData |
| Network Requests | | HTTP calls, API requests |
| File I/O | | Local storage, database operations |
| Compute Intensive | | JSON parsing, sorting, encryption |
Correct Usage:
kotlin
// In ViewModel
viewModelScope.launch {
// Default Main thread, can update UI State
_uiState.value = UiState.Loading
// Switch to IO thread for network request
val result = withContext(Dispatchers.IO) {
repository.fetchData()
}
// Automatically returns to Main thread, update UI
_uiState.value = UiState.Success(result)
}
// In Repository (suspend functions should be main-safe)
suspend fun fetchData(): Data = withContext(Dispatchers.IO) {
api.getData()
}Common Mistakes:
kotlin
// ❌ Wrong: Updating UI on IO thread
viewModelScope.launch(Dispatchers.IO) {
val data = api.fetch()
_uiState.value = data // Crash or warning!
}
// ❌ Wrong: Executing time-consuming operation on Main thread
viewModelScope.launch {
val data = api.fetch() // Blocking main thread! ANR
}
// ✅ Correct: Fetch on IO, update on Main
viewModelScope.launch {
val data = withContext(Dispatchers.IO) { api.fetch() }
_uiState.value = data
}线程选择原则:
| 操作类型 | 线程 | 说明 |
|---|---|---|
| UI更新 | | 更新视图、状态、LiveData |
| 网络请求 | | HTTP调用、API请求 |
| 文件I/O | | 本地存储、数据库操作 |
| 计算密集型操作 | | JSON解析、排序、加密 |
正确用法:
kotlin
// In ViewModel
viewModelScope.launch {
// Default Main thread, can update UI State
_uiState.value = UiState.Loading
// Switch to IO thread for network request
val result = withContext(Dispatchers.IO) {
repository.fetchData()
}
// Automatically returns to Main thread, update UI
_uiState.value = UiState.Success(result)
}
// In Repository (suspend functions should be main-safe)
suspend fun fetchData(): Data = withContext(Dispatchers.IO) {
api.getData()
}常见错误:
kotlin
// ❌ Wrong: Updating UI on IO thread
viewModelScope.launch(Dispatchers.IO) {
val data = api.fetch()
_uiState.value = data // Crash or warning!
}
// ❌ Wrong: Executing time-consuming operation on Main thread
viewModelScope.launch {
val data = api.fetch() // Blocking main thread! ANR
}
// ✅ Correct: Fetch on IO, update on Main
viewModelScope.launch {
val data = withContext(Dispatchers.IO) { api.fetch() }
_uiState.value = data
}3.4 Visibility Rules
3.4 可见性规则
kotlin
// Default is public, declare explicitly when needed
class UserRepository { // public
private val cache = mutableMapOf<String, User>() // Visible only within class
internal fun clearCache() {} // Visible only within module
}
// data class properties are public by default, be careful when used across modules
data class User(
val id: String, // public
val name: String
)kotlin
// Default is public, declare explicitly when needed
class UserRepository { // public
private val cache = mutableMapOf<String, User>() // Visible only within class
internal fun clearCache() {} // Visible only within module
}
// data class properties are public by default, be careful when used across modules
data class User(
val id: String, // public
val name: String
)3.5 Common Syntax Pitfalls
3.5 常见语法陷阱
kotlin
// ❌ Wrong: Accessing uninitialized lateinit
class MyViewModel : ViewModel() {
lateinit var data: String
fun process() = data.length // May crash
}
// ✅ Correct: Use nullable or default value
class MyViewModel : ViewModel() {
var data: String? = null
fun process() = data?.length ?: 0
}
// ❌ Wrong: Using return in lambda
list.forEach { item ->
if (item.isEmpty()) return // Returns from outer function!
}
// ✅ Correct: Use return@forEach
list.forEach { item ->
if (item.isEmpty()) return@forEach
}kotlin
// ❌ Wrong: Accessing uninitialized lateinit
class MyViewModel : ViewModel() {
lateinit var data: String
fun process() = data.length // May crash
}
// ✅ Correct: Use nullable or default value
class MyViewModel : ViewModel() {
var data: String? = null
fun process() = data?.length ?: 0
}
// ❌ Wrong: Using return in lambda
list.forEach { item ->
if (item.isEmpty()) return // Returns from outer function!
}
// ✅ Correct: Use return@forEach
list.forEach { item ->
if (item.isEmpty()) return@forEach
}3.6 Server Response Data Class Fields Must Be Nullable
3.6 服务端响应数据类字段必须为可空类型
kotlin
// ❌ Wrong: Fields declared as non-null (server may not return them)
data class UserResponse(
val id: String = "",
val name: String = "",
val avatar: String = ""
)
// ✅ Correct: All fields declared as nullable
data class UserResponse(
@SerializedName("id")
val id: String? = null,
@SerializedName("name")
val name: String? = null,
@SerializedName("avatar")
val avatar: String? = null
)kotlin
// ❌ Wrong: Fields declared as non-null (server may not return them)
data class UserResponse(
val id: String = "",
val name: String = "",
val avatar: String = ""
)
// ✅ Correct: All fields declared as nullable
data class UserResponse(
@SerializedName("id")
val id: String? = null,
@SerializedName("name")
val name: String? = null,
@SerializedName("avatar")
val avatar: String? = null
)3.7 Lifecycle Resource Management
3.7 生命周期资源管理
kotlin
// ❌ Wrong: Only adding Observer, not removing
class MyView : View {
override fun onAttachedToWindow() {
super.onAttachedToWindow()
activity?.lifecycle?.addObserver(this)
}
// Memory leak!
}
// ✅ Correct: Paired add and remove
class MyView : View {
override fun onAttachedToWindow() {
super.onAttachedToWindow()
activity?.lifecycle?.addObserver(this)
}
override fun onDetachedFromWindow() {
activity?.lifecycle?.removeObserver(this)
super.onDetachedFromWindow()
}
}kotlin
// ❌ Wrong: Only adding Observer, not removing
class MyView : View {
override fun onAttachedToWindow() {
super.onAttachedToWindow()
activity?.lifecycle?.addObserver(this)
}
// Memory leak!
}
// ✅ Correct: Paired add and remove
class MyView : View {
override fun onAttachedToWindow() {
super.onAttachedToWindow()
activity?.lifecycle?.addObserver(this)
}
override fun onDetachedFromWindow() {
activity?.lifecycle?.removeObserver(this)
super.onDetachedFromWindow()
}
}3.8 Logging Level Usage
3.8 日志级别使用
kotlin
import android.util.Log
// Info: Key checkpoints in normal flow
Log.i(TAG, "loadData: started, userId = $userId")
// Warning: Abnormal but recoverable situations
Log.w(TAG, "loadData: cache miss, fallback to network")
// Error: Failure/error situations
Log.e(TAG, "loadData failed: ${error.message}")| Level | Use Case |
|---|---|
| Normal flow, method entry, key parameters |
| Recoverable exceptions, fallback handling, null returns |
| Request failures, caught exceptions, unrecoverable errors |
kotlin
import android.util.Log
// Info: Key checkpoints in normal flow
Log.i(TAG, "loadData: started, userId = $userId")
// Warning: Abnormal but recoverable situations
Log.w(TAG, "loadData: cache miss, fallback to network")
// Error: Failure/error situations
Log.e(TAG, "loadData failed: ${error.message}")| 级别 | 使用场景 |
|---|---|
| 正常流程、方法入口、关键参数 |
| 可恢复异常、降级处理、空返回值 |
| 请求失败、捕获到的异常、不可恢复错误 |
4. Jetpack Compose Standards
4. Jetpack Compose规范
4.1 @Composable Context Rules
4.1 @Composable上下文规则
kotlin
// ❌ Wrong: Calling Composable from non-Composable function
fun showError(message: String) {
Text(message) // Compile error!
}
// ✅ Correct: Mark as @Composable
@Composable
fun ErrorMessage(message: String) {
Text(message)
}
// ❌ Wrong: Using suspend outside LaunchedEffect
@Composable
fun MyScreen() {
val data = fetchData() // Error!
}
// ✅ Correct: Use LaunchedEffect
@Composable
fun MyScreen() {
var data by remember { mutableStateOf<Data?>(null) }
LaunchedEffect(Unit) {
data = fetchData()
}
}kotlin
// ❌ Wrong: Calling Composable from non-Composable function
fun showError(message: String) {
Text(message) // Compile error!
}
// ✅ Correct: Mark as @Composable
@Composable
fun ErrorMessage(message: String) {
Text(message)
}
// ❌ Wrong: Using suspend outside LaunchedEffect
@Composable
fun MyScreen() {
val data = fetchData() // Error!
}
// ✅ Correct: Use LaunchedEffect
@Composable
fun MyScreen() {
var data by remember { mutableStateOf<Data?>(null) }
LaunchedEffect(Unit) {
data = fetchData()
}
}4.2 State Management
4.2 状态管理
kotlin
// Basic State
var count by remember { mutableStateOf(0) }
// Derived State (avoid redundant computation)
val isEven by remember { derivedStateOf { count % 2 == 0 } }
// Persist across recomposition (e.g., scroll position)
val scrollState = rememberScrollState()
// State in ViewModel
class MyViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
}kotlin
// Basic State
var count by remember { mutableStateOf(0) }
// Derived State (avoid redundant computation)
val isEven by remember { derivedStateOf { count % 2 == 0 } }
// Persist across recomposition (e.g., scroll position)
val scrollState = rememberScrollState()
// State in ViewModel
class MyViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
}4.3 Common Compose Mistakes
4.3 Compose常见错误
kotlin
// ❌ Wrong: Creating objects in Composable (created on every recomposition)
@Composable
fun MyScreen() {
val viewModel = MyViewModel() // Wrong!
}
// ✅ Correct: Use viewModel() or remember
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
// ...
}kotlin
// ❌ Wrong: Creating objects in Composable (created on every recomposition)
@Composable
fun MyScreen() {
val viewModel = MyViewModel() // Wrong!
}
// ✅ Correct: Use viewModel() or remember
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
// ...
}5. Resources & Icons
5. 资源与图标
5.1 App Icon Requirements
5.1 应用图标要求
Must provide multi-resolution icons:
| Directory | Size | Purpose |
|---|---|---|
| mipmap-mdpi | 48x48 | Baseline |
| mipmap-hdpi | 72x72 | 1.5x |
| mipmap-xhdpi | 96x96 | 2x |
| mipmap-xxhdpi | 144x144 | 3x |
| mipmap-xxxhdpi | 192x192 | 4x |
Recommended: Use Adaptive Icon (Android 8+):
xml
<!-- res/mipmap-anydpi-v26/ic_launcher.xml -->
<adaptive-icon>
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>必须提供多分辨率图标:
| 目录 | 尺寸 | 用途 |
|---|---|---|
| mipmap-mdpi | 48x48 | 基准分辨率 |
| mipmap-hdpi | 72x72 | 1.5倍密度 |
| mipmap-xhdpi | 96x96 | 2倍密度 |
| mipmap-xxhdpi | 144x144 | 3倍密度 |
| mipmap-xxxhdpi | 192x192 | 4倍密度 |
推荐使用自适应图标(Android 8及以上):
xml
<!-- res/mipmap-anydpi-v26/ic_launcher.xml -->
<adaptive-icon>
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>5.2 Resource Naming Conventions
5.2 资源命名规范
| Type | Prefix | Example |
|---|---|---|
| Layout | layout_ | |
| Image | ic_, img_, bg_ | |
| Color | color_ | |
| String | - | |
| 类型 | 前缀 | 示例 |
|---|---|---|
| 布局文件 | layout_ | |
| 图片资源 | ic_, img_, bg_ | |
| 颜色资源 | color_ | |
| 字符串资源 | - | |
5.3 Avoid Android Reserved Names (Important)
5.3 避免使用Android保留名称(重点)
Variable names, resource IDs, colors, icons, and XML elements must not use Android reserved words or system resource names. Using reserved names causes build errors or resource conflicts.
Common Reserved Names to Avoid:
| Category | Reserved Names (Do NOT Use) |
|---|---|
| Colors | |
| Icons/Drawables | |
| Views | |
| Attributes | |
| System | |
Examples:
xml
<!-- ❌ Wrong: Using reserved names -->
<color name="background">#FFFFFF</color>
<color name="icon">#000000</color>
<!-- ✅ Correct: Add prefix or specific naming -->
<color name="app_background">#FFFFFF</color>
<color name="icon_primary">#000000</color>kotlin
// ❌ Wrong: Variable names conflict with system
val icon = R.drawable.my_icon
val background = Color.White
// ✅ Correct: Use descriptive names
val appIcon = R.drawable.my_icon
val screenBackground = Color.Whitexml
<!-- ❌ Wrong: Drawable name conflicts -->
<ImageView android:src="@drawable/icon" />
<!-- ✅ Correct: Add prefix -->
<ImageView android:src="@drawable/ic_home" />变量名、资源ID、颜色、图标以及XML元素严禁使用Android保留字或系统资源名称。使用保留名称会导致构建错误或资源冲突。
常见需避免的保留名称:
| 类别 | 保留名称(请勿使用) |
|---|---|
| 颜色 | |
| 图标/Drawable | |
| 视图 | |
| 属性 | |
| 系统相关 | |
示例:
xml
<!-- ❌ Wrong: Using reserved names -->
<color name="background">#FFFFFF</color>
<color name="icon">#000000</color>
<!-- ✅ Correct: Add prefix or specific naming -->
<color name="app_background">#FFFFFF</color>
<color name="icon_primary">#000000</color>kotlin
// ❌ Wrong: Variable names conflict with system
val icon = R.drawable.my_icon
val background = Color.White
// ✅ Correct: Use descriptive names
val appIcon = R.drawable.my_icon
val screenBackground = Color.Whitexml
<!-- ❌ Wrong: Drawable name conflicts -->
<ImageView android:src="@drawable/icon" />
<!-- ✅ Correct: Add prefix -->
<ImageView android:src="@drawable/ic_home" />6. Build Error Diagnosis & Fixes
6. 构建错误诊断与修复
6.1 Common Error Quick Reference
6.1 常见错误速查
| Error Keyword | Cause | Fix |
|---|---|---|
| Missing import or undefined | Check imports, verify dependencies |
| Type incompatibility | Check parameter types, add conversion |
| Visibility issue | Check public/private/internal |
| Composable context error | Ensure caller is also @Composable |
| Dependency conflict | Use |
| Resource file error | Check XML syntax and resource references |
| 错误关键词 | 原因 | 修复方案 |
|---|---|---|
| 缺失导入或未定义符号 | 检查导入语句,验证依赖是否正确 |
| 类型不兼容 | 检查参数类型,添加类型转换 |
| 可见性问题 | 检查public/private/internal修饰符 |
| Composable上下文错误 | 确保调用方也标记为@Composable |
| 依赖冲突 | 使用 |
| 资源文件错误 | 检查XML语法和资源引用 |
6.2 Fix Best Practices
6.2 修复最佳实践
- Read the complete error message first: Locate file and line number
- Check recent changes: Problems usually in latest modifications
- Clean Build:
./gradlew clean assembleDebug - Check dependency versions: Version conflicts are common causes
- Refresh dependencies if needed: Clear cache and rebuild
- 先阅读完整错误信息:定位到具体文件和行号
- 检查最近的修改:问题通常出在最新的变更中
- 清理并重新构建:执行
./gradlew clean assembleDebug - 检查依赖版本:版本冲突是常见原因
- 必要时刷新依赖:清除缓存后重新构建
6.3 Debugging Commands
6.3 调试命令
bash
undefinedbash
undefinedClean and build
Clean and build
./gradlew clean assembleDebug
./gradlew clean assembleDebug
View dependency tree (investigate conflicts)
View dependency tree (investigate conflicts)
./gradlew :app:dependencies
./gradlew :app:dependencies
View detailed errors
View detailed errors
./gradlew assembleDebug --stacktrace
./gradlew assembleDebug --stacktrace
Refresh dependencies
Refresh dependencies
./gradlew --refresh-dependencies
---./gradlew --refresh-dependencies
---7. Material Design 3 Guidelines
7. Material Design 3设计指南
Review Android UI files for compliance with Material Design 3 Guidelines and Android best practices.
检查Android UI文件是否符合Material Design 3指南和Android最佳实践。
Design Philosophy
设计理念
M3 Core Principles
M3核心原则
| Principle | Description |
|---|---|
| Personal | Dynamic color based on user preferences and wallpaper |
| Adaptive | Responsive across all screen sizes and form factors |
| Expressive | Bold colors and typography with personality |
| Accessible | Inclusive design for all users |
| 原则 | 说明 |
|---|---|
| 个性化 | 基于用户偏好和壁纸的动态配色 |
| 自适应 | 在所有屏幕尺寸和设备形态下响应式适配 |
| 表现力 | 兼具个性的大胆色彩与排版 |
| 无障碍 | 面向所有用户的包容性设计 |
M3 Expressive (Latest)
M3表现力升级(最新)
The latest evolution adds emotion-driven UX through:
- Vibrant, dynamic colors
- Intuitive motion physics
- Adaptive components
- Flexible typography
- Contrasting shapes (35 new shape options)
最新版本通过以下方式增加情感化用户体验:
- 鲜艳的动态色彩
- 直观的动效物理特性
- 自适应组件
- 灵活的排版
- 对比鲜明的形状(新增35种形状选项)
App Style Selection
应用风格选择
Critical Decision: Match visual style to app category and target audience.
| App Category | Visual Style | Key Characteristics |
|---|---|---|
| Utility/Tool | Minimalist | Clean, efficient, neutral colors |
| Finance/Banking | Professional Trust | Conservative colors, security-focused |
| Health/Wellness | Calm & Natural | Soft colors, organic shapes |
| Kids (3-5) | Playful Simple | Bright colors, large targets (56dp+) |
| Kids (6-12) | Fun & Engaging | Vibrant, gamified feedback |
| Social/Entertainment | Expressive | Brand-driven, gesture-rich |
| Productivity | Clean & Focused | Minimal, high contrast |
| E-commerce | Conversion-focused | Clear CTAs, scannable |
See Design Style Guide for detailed style profiles.
关键决策:视觉风格需与应用类别和目标受众匹配。
| 应用类别 | 视觉风格 | 核心特征 |
|---|---|---|
| 工具类 | 极简风格 | 简洁、高效、中性配色 |
| 金融/银行 | 专业可信风格 | 保守配色、聚焦安全性 |
| 健康/养生 | 舒缓自然风格 | 柔和色彩、有机形状 |
| 儿童(3-5岁) | 趣味简约风格 | 明亮色彩、大目标区域(56dp以上) |
| 儿童(6-12岁) | 趣味互动风格 | 鲜艳色彩、游戏化反馈 |
| 社交/娱乐 | 表现力风格 | 品牌驱动、丰富手势 |
| 生产力工具 | 简洁聚焦风格 | 极简、高对比度 |
| 电商 | 转化导向风格 | 清晰的CTA、易扫描布局 |
查看设计风格指南获取详细风格配置。
Quick Reference: Key Specifications
快速参考:关键规格
Color Contrast Requirements
色彩对比度要求
| Element | Minimum Ratio |
|---|---|
| Body text | 4.5:1 |
| Large text (18sp+) | 3:1 |
| UI components | 3:1 |
| 元素 | 最小对比度 |
|---|---|
| 正文文本 | 4.5:1 |
| 大文本(18sp及以上) | 3:1 |
| UI组件 | 3:1 |
Touch Targets
触摸目标区域
| Type | Size |
|---|---|
| Minimum | 48 × 48dp |
| Recommended (primary actions) | 56 × 56dp |
| Kids apps | 56dp+ |
| Spacing between targets | 8dp minimum |
| 类型 | 尺寸 |
|---|---|
| 最小值 | 48 × 48dp |
| 推荐值(主要操作) | 56 × 56dp |
| 儿童应用 | 56dp以上 |
| 目标间距 | 最小8dp |
8dp Grid System
8dp网格系统
| Token | Value | Usage |
|---|---|---|
| xs | 4dp | Icon padding |
| sm | 8dp | Tight spacing |
| md | 16dp | Default padding |
| lg | 24dp | Section spacing |
| xl | 32dp | Large gaps |
| xxl | 48dp | Screen margins |
| 标记 | 数值 | 用途 |
|---|---|---|
| xs | 4dp | 图标内边距 |
| sm | 8dp | 紧凑间距 |
| md | 16dp | 默认内边距 |
| lg | 24dp | 区块间距 |
| xl | 32dp | 大间距 |
| xxl | 48dp | 屏幕边距 |
Typography Scale (Summary)
排版尺度(摘要)
| Category | Sizes |
|---|---|
| Display | 57sp, 45sp, 36sp |
| Headline | 32sp, 28sp, 24sp |
| Title | 22sp, 16sp, 14sp |
| Body | 16sp, 14sp, 12sp |
| Label | 14sp, 12sp, 11sp |
| 类别 | 尺寸 |
|---|---|
| Display | 57sp, 45sp, 36sp |
| Headline | 32sp, 28sp, 24sp |
| Title | 22sp, 16sp, 14sp |
| Body | 16sp, 14sp, 12sp |
| Label | 14sp, 12sp, 11sp |
Animation Duration
动画时长
| Type | Duration |
|---|---|
| Micro (ripples) | 50-100ms |
| Short (simple) | 100-200ms |
| Medium (expand/collapse) | 200-300ms |
| Long (complex) | 300-500ms |
| 类型 | 时长 |
|---|---|
| 微交互(如水波纹) | 50-100ms |
| 短动画(简单操作) | 100-200ms |
| 中等动画(展开/收起) | 200-300ms |
| 长动画(复杂操作) | 300-500ms |
Component Dimensions
组件尺寸
| Component | Height | Min Width |
|---|---|---|
| Button | 40dp | 64dp |
| FAB | 56dp | 56dp |
| Text Field | 56dp | 280dp |
| App Bar | 64dp | - |
| Bottom Nav | 80dp | - |
| 组件 | 高度 | 最小宽度 |
|---|---|---|
| 按钮 | 40dp | 64dp |
| 悬浮操作按钮(FAB) | 56dp | 56dp |
| 文本输入框 | 56dp | 280dp |
| 应用栏 | 64dp | - |
| 底部导航栏 | 80dp | - |
Anti-Patterns (Must Avoid)
反模式(必须避免)
UI Anti-Patterns
UI反模式
- More than 5 bottom navigation items
- Multiple FABs on same screen
- Touch targets smaller than 48dp
- Inconsistent spacing (non-8dp multiples)
- Missing dark theme support
- Text on colored backgrounds without contrast check
- 底部导航项超过5个
- 同一屏幕存在多个FAB
- 触摸目标区域小于48dp
- 间距不一致(非8dp倍数)
- 未支持深色主题
- 彩色背景上的文本未做对比度检查
Performance Anti-Patterns
性能反模式
- Startup time > 2 seconds without progress indicator
- Frame rate < 60 FPS (> 16ms per frame)
- Crash rate > 1.09% (Google Play threshold)
- ANR rate > 0.47% (Google Play threshold)
- 启动时间超过2秒且无进度指示器
- 帧率低于60 FPS(每帧耗时超过16ms)
- 崩溃率超过1.09%(Google Play阈值)
- ANR率超过0.47%(Google Play阈值)
Accessibility Anti-Patterns
无障碍反模式
- Missing contentDescription on interactive elements
- Element type in labels (e.g., "Save button" instead of "Save")
- Complex gestures in kids apps
- Text-only buttons for non-readers
- 交互元素缺失contentDescription
- 标签中包含元素类型(例如“保存按钮”而非“保存”)
- 儿童应用中使用复杂手势
- 面向非阅读用户的纯文本按钮
Review Checklist
审核清单
- 8dp spacing grid compliance
- 48dp minimum touch targets
- Proper typography scale usage
- Color contrast compliance (4.5:1+ for text)
- Dark theme support
- contentDescription on all interactive elements
- Startup < 2 seconds or shows progress
- Visual style matches app category
- 符合8dp间距网格规范
- 触摸目标区域不小于48dp
- 正确使用排版尺度
- 色彩对比度符合要求(文本对比度≥4.5:1)
- 支持深色主题
- 所有交互元素都设置了contentDescription
- 启动时间小于2秒或显示进度指示器
- 视觉风格与应用类别匹配
Design References
设计参考
| Topic | Reference |
|---|---|
| Colors, Typography, Spacing, Shapes | Visual Design |
| Animation & Transitions | Motion System |
| Accessibility Guidelines | Accessibility |
| Large Screens & Foldables | Adaptive Screens |
| Android Vitals & Performance | Performance & Stability |
| Privacy & Security | Privacy & Security |
| Audio, Video, Notifications | Functional Requirements |
| App Style by Category | Design Style Guide |
| 主题 | 参考文档 |
|---|---|
| 色彩、排版、间距、形状 | 视觉设计 |
| 动画与过渡 | 动效系统 |
| 无障碍指南 | 无障碍设计 |
| 大屏幕与折叠屏 | 自适应屏幕 |
| Android核心指标与性能 | 性能与稳定性 |
| 隐私与安全 | 隐私与安全 |
| 音频、视频、通知 | 功能需求 |
| 按类别划分的应用风格 | 设计风格指南 |