android-native-dev

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

1. Project Scenario Assessment

1. 项目场景评估

Before starting development, assess the current project state:
ScenarioCharacteristicsApproach
Empty DirectoryNo files presentFull initialization required, including Gradle Wrapper
Has Gradle Wrapper
gradlew
and
gradle/wrapper/
exist
Use
./gradlew
directly for builds
Android Studio ProjectComplete project structure, may lack wrapperCheck wrapper, run
gradle wrapper
if needed
Incomplete ProjectPartial files presentCheck missing files, complete configuration
Key Principles:
  • Before writing business logic, ensure
    ./gradlew assembleDebug
    succeeds
  • If
    gradle.properties
    is missing, create it first and configure AndroidX
开始开发前,请先评估当前项目状态:
场景特征处理方式
空目录无任何文件需要完成完整初始化,包括Gradle Wrapper
已包含Gradle Wrapper存在
gradlew
gradle/wrapper/
直接使用
./gradlew
进行构建
Android Studio项目完整项目结构,可能缺少Wrapper检查Wrapper,若缺失则运行
gradle wrapper
不完整项目仅存在部分文件检查缺失文件,补全配置
核心原则:
  • 编写业务逻辑前,确保
    ./gradlew assembleDebug
    执行成功
  • 若缺失
    gradle.properties
    ,请先创建并配置AndroidX

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 icons

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 icons

2. Project Configuration

2. 项目配置

2.1 gradle.properties

2.1 gradle.properties

properties
undefined
properties
undefined

Required 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:
{flavor}{BuildType}
→ e.g.,
devDebug
,
prodRelease
Gradle 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}
→ 例如
devDebug
,
prodRelease
Gradle构建命令:
bash
undefined

List 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 code
Multiple 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 命名规范

TypeConventionExample
Class/InterfacePascalCase
UserRepository
,
MainActivity
Function/VariablecamelCase
getUserName()
,
isLoading
ConstantSCREAMING_SNAKE
MAX_RETRY_COUNT
Packagelowercase
com.example.myapp
ComposablePascalCase
@Composable fun UserCard()
类型规范示例
类/接口大驼峰式(PascalCase)
UserRepository
,
MainActivity
函数/变量小驼峰式(camelCase)
getUserName()
,
isLoading
常量大写蛇形式(SCREAMING_SNAKE)
MAX_RETRY_COUNT
包名全小写
com.example.myapp
可组合函数大驼峰式(PascalCase)
@Composable fun UserCard()

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 TypeThreadDescription
UI Updates
Dispatchers.Main
Update View, State, LiveData
Network Requests
Dispatchers.IO
HTTP calls, API requests
File I/O
Dispatchers.IO
Local storage, database operations
Compute Intensive
Dispatchers.Default
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更新
Dispatchers.Main
更新视图、状态、LiveData
网络请求
Dispatchers.IO
HTTP调用、API请求
文件I/O
Dispatchers.IO
本地存储、数据库操作
计算密集型操作
Dispatchers.Default
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}")
LevelUse Case
i
(Info)
Normal flow, method entry, key parameters
w
(Warning)
Recoverable exceptions, fallback handling, null returns
e
(Error)
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}")
级别使用场景
i
(Info)
正常流程、方法入口、关键参数
w
(Warning)
可恢复异常、降级处理、空返回值
e
(Error)
请求失败、捕获到的异常、不可恢复错误

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:
DirectorySizePurpose
mipmap-mdpi48x48Baseline
mipmap-hdpi72x721.5x
mipmap-xhdpi96x962x
mipmap-xxhdpi144x1443x
mipmap-xxxhdpi192x1924x
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-mdpi48x48基准分辨率
mipmap-hdpi72x721.5倍密度
mipmap-xhdpi96x962倍密度
mipmap-xxhdpi144x1443倍密度
mipmap-xxxhdpi192x1924倍密度
推荐使用自适应图标(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 资源命名规范

TypePrefixExample
Layoutlayout_
layout_main.xml
Imageic_, img_, bg_
ic_user.png
Colorcolor_
color_primary
String-
app_name
,
btn_submit
类型前缀示例
布局文件layout_
layout_main.xml
图片资源ic_, img_, bg_
ic_user.png
颜色资源color_
color_primary
字符串资源-
app_name
,
btn_submit

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:
CategoryReserved Names (Do NOT Use)
Colors
background
,
foreground
,
transparent
,
white
,
black
Icons/Drawables
icon
,
logo
,
image
,
drawable
Views
view
,
text
,
button
,
layout
,
container
Attributes
id
,
name
,
type
,
style
,
theme
,
color
System
app
,
android
,
content
,
data
,
action
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.White
xml
<!-- ❌ Wrong: Drawable name conflicts -->
<ImageView android:src="@drawable/icon" />

<!-- ✅ Correct: Add prefix -->
<ImageView android:src="@drawable/ic_home" />

变量名、资源ID、颜色、图标以及XML元素严禁使用Android保留字或系统资源名称。使用保留名称会导致构建错误或资源冲突。
常见需避免的保留名称:
类别保留名称(请勿使用)
颜色
background
,
foreground
,
transparent
,
white
,
black
图标/Drawable
icon
,
logo
,
image
,
drawable
视图
view
,
text
,
button
,
layout
,
container
属性
id
,
name
,
type
,
style
,
theme
,
color
系统相关
app
,
android
,
content
,
data
,
action
示例:
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.White
xml
<!-- ❌ 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 KeywordCauseFix
Unresolved reference
Missing import or undefinedCheck imports, verify dependencies
Type mismatch
Type incompatibilityCheck parameter types, add conversion
Cannot access
Visibility issueCheck public/private/internal
@Composable invocations
Composable context errorEnsure caller is also @Composable
Duplicate class
Dependency conflictUse
./gradlew dependencies
to investigate
AAPT: error
Resource file errorCheck XML syntax and resource references
错误关键词原因修复方案
Unresolved reference
缺失导入或未定义符号检查导入语句,验证依赖是否正确
Type mismatch
类型不兼容检查参数类型,添加类型转换
Cannot access
可见性问题检查public/private/internal修饰符
@Composable invocations
Composable上下文错误确保调用方也标记为@Composable
Duplicate class
依赖冲突使用
./gradlew dependencies
排查冲突
AAPT: error
资源文件错误检查XML语法和资源引用

6.2 Fix Best Practices

6.2 修复最佳实践

  1. Read the complete error message first: Locate file and line number
  2. Check recent changes: Problems usually in latest modifications
  3. Clean Build:
    ./gradlew clean assembleDebug
  4. Check dependency versions: Version conflicts are common causes
  5. Refresh dependencies if needed: Clear cache and rebuild
  1. 先阅读完整错误信息:定位到具体文件和行号
  2. 检查最近的修改:问题通常出在最新的变更中
  3. 清理并重新构建:执行
    ./gradlew clean assembleDebug
  4. 检查依赖版本:版本冲突是常见原因
  5. 必要时刷新依赖:清除缓存后重新构建

6.3 Debugging Commands

6.3 调试命令

bash
undefined
bash
undefined

Clean 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核心原则

PrincipleDescription
PersonalDynamic color based on user preferences and wallpaper
AdaptiveResponsive across all screen sizes and form factors
ExpressiveBold colors and typography with personality
AccessibleInclusive 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 CategoryVisual StyleKey Characteristics
Utility/ToolMinimalistClean, efficient, neutral colors
Finance/BankingProfessional TrustConservative colors, security-focused
Health/WellnessCalm & NaturalSoft colors, organic shapes
Kids (3-5)Playful SimpleBright colors, large targets (56dp+)
Kids (6-12)Fun & EngagingVibrant, gamified feedback
Social/EntertainmentExpressiveBrand-driven, gesture-rich
ProductivityClean & FocusedMinimal, high contrast
E-commerceConversion-focusedClear CTAs, scannable
See Design Style Guide for detailed style profiles.
关键决策:视觉风格需与应用类别和目标受众匹配。
应用类别视觉风格核心特征
工具类极简风格简洁、高效、中性配色
金融/银行专业可信风格保守配色、聚焦安全性
健康/养生舒缓自然风格柔和色彩、有机形状
儿童(3-5岁)趣味简约风格明亮色彩、大目标区域(56dp以上)
儿童(6-12岁)趣味互动风格鲜艳色彩、游戏化反馈
社交/娱乐表现力风格品牌驱动、丰富手势
生产力工具简洁聚焦风格极简、高对比度
电商转化导向风格清晰的CTA、易扫描布局
查看设计风格指南获取详细风格配置。

Quick Reference: Key Specifications

快速参考:关键规格

Color Contrast Requirements

色彩对比度要求

ElementMinimum Ratio
Body text4.5:1
Large text (18sp+)3:1
UI components3:1
元素最小对比度
正文文本4.5:1
大文本(18sp及以上)3:1
UI组件3:1

Touch Targets

触摸目标区域

TypeSize
Minimum48 × 48dp
Recommended (primary actions)56 × 56dp
Kids apps56dp+
Spacing between targets8dp minimum
类型尺寸
最小值48 × 48dp
推荐值(主要操作)56 × 56dp
儿童应用56dp以上
目标间距最小8dp

8dp Grid System

8dp网格系统

TokenValueUsage
xs4dpIcon padding
sm8dpTight spacing
md16dpDefault padding
lg24dpSection spacing
xl32dpLarge gaps
xxl48dpScreen margins
标记数值用途
xs4dp图标内边距
sm8dp紧凑间距
md16dp默认内边距
lg24dp区块间距
xl32dp大间距
xxl48dp屏幕边距

Typography Scale (Summary)

排版尺度(摘要)

CategorySizes
Display57sp, 45sp, 36sp
Headline32sp, 28sp, 24sp
Title22sp, 16sp, 14sp
Body16sp, 14sp, 12sp
Label14sp, 12sp, 11sp
类别尺寸
Display57sp, 45sp, 36sp
Headline32sp, 28sp, 24sp
Title22sp, 16sp, 14sp
Body16sp, 14sp, 12sp
Label14sp, 12sp, 11sp

Animation Duration

动画时长

TypeDuration
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

组件尺寸

ComponentHeightMin Width
Button40dp64dp
FAB56dp56dp
Text Field56dp280dp
App Bar64dp-
Bottom Nav80dp-
组件高度最小宽度
按钮40dp64dp
悬浮操作按钮(FAB)56dp56dp
文本输入框56dp280dp
应用栏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

设计参考

TopicReference
Colors, Typography, Spacing, ShapesVisual Design
Animation & TransitionsMotion System
Accessibility GuidelinesAccessibility
Large Screens & FoldablesAdaptive Screens
Android Vitals & PerformancePerformance & Stability
Privacy & SecurityPrivacy & Security
Audio, Video, NotificationsFunctional Requirements
App Style by CategoryDesign Style Guide
主题参考文档
色彩、排版、间距、形状视觉设计
动画与过渡动效系统
无障碍指南无障碍设计
大屏幕与折叠屏自适应屏幕
Android核心指标与性能性能与稳定性
隐私与安全隐私与安全
音频、视频、通知功能需求
按类别划分的应用风格设计风格指南