android-jetpack-compose-expert
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAndroid Jetpack Compose Expert
Android Jetpack Compose 专家指南
Overview
概述
A comprehensive guide for building production-quality Android applications using Jetpack Compose. This skill covers architectural patterns, state management with ViewModels, navigation type-safety, and performance optimization techniques.
这是一份使用Jetpack Compose构建生产级Android应用的综合指南。本指南涵盖架构模式、结合ViewModel的状态管理、类型安全导航以及性能优化技巧。
When to Use This Skill
适用场景
- Use when starting a new Android project with Jetpack Compose.
- Use when migrating legacy XML layouts to Compose.
- Use when implementing complex UI state management and side effects.
- Use when optimizing Compose performance (recomposition counts, stability).
- Use when setting up Navigation with type safety.
- 在使用Jetpack Compose启动新Android项目时使用。
- 在将传统XML布局迁移到Compose时使用。
- 在实现复杂UI状态管理和副作用处理时使用。
- 在优化Compose性能(重组次数、稳定性)时使用。
- 在设置类型安全导航时使用。
Step-by-Step Guide
分步指南
1. Project Setup & Dependencies
1. 项目设置与依赖
Ensure your includes the necessary Compose BOM and libraries.
libs.versions.tomlkotlin
[versions]
composeBom = "2024.02.01"
activityCompose = "1.8.2"
[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }确保你的包含必要的Compose BOM和库。
libs.versions.tomlkotlin
[versions]
composeBom = "2024.02.01"
activityCompose = "1.8.2"
[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }2. State Management Pattern (MVI/MVVM)
2. 状态管理模式(MVI/MVVM)
Use with to expose UI state. Avoid exposing .
ViewModelStateFlowMutableStateFlowkotlin
// UI State Definition
data class UserUiState(
val isLoading: Boolean = false,
val user: User? = null,
val error: String? = null
)
// ViewModel
class UserViewModel @Inject constructor(
private val userRepository: UserRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(UserUiState())
val uiState: StateFlow<UserUiState> = _uiState.asStateFlow()
fun loadUser() {
viewModelScope.launch {
_uiState.update { it.copy(isLoading = true) }
try {
val user = userRepository.getUser()
_uiState.update { it.copy(user = user, isLoading = false) }
} catch (e: Exception) {
_uiState.update { it.copy(error = e.message, isLoading = false) }
}
}
}
}结合使用来暴露UI状态。避免暴露。
StateFlowViewModelMutableStateFlowkotlin
// UI State Definition
data class UserUiState(
val isLoading: Boolean = false,
val user: User? = null,
val error: String? = null
)
// ViewModel
class UserViewModel @Inject constructor(
private val userRepository: UserRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(UserUiState())
val uiState: StateFlow<UserUiState> = _uiState.asStateFlow()
fun loadUser() {
viewModelScope.launch {
_uiState.update { it.copy(isLoading = true) }
try {
val user = userRepository.getUser()
_uiState.update { it.copy(user = user, isLoading = false) }
} catch (e: Exception) {
_uiState.update { it.copy(error = e.message, isLoading = false) }
}
}
}
}3. Creating the Screen Composable
3. 创建屏幕可组合项
Consume the state in a "Screen" composable and pass data down to stateless components.
kotlin
@Composable
fun UserScreen(
viewModel: UserViewModel = hiltViewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
UserContent(
uiState = uiState,
onRetry = viewModel::loadUser
)
}
@Composable
fun UserContent(
uiState: UserUiState,
onRetry: () -> Unit
) {
Scaffold { padding ->
Box(modifier = Modifier.padding(padding)) {
when {
uiState.isLoading -> CircularProgressIndicator()
uiState.error != null -> ErrorView(uiState.error, onRetry)
uiState.user != null -> UserProfile(uiState.user)
}
}
}
}在「屏幕」可组合项中消费状态,并将数据向下传递给无状态组件。
kotlin
@Composable
fun UserScreen(
viewModel: UserViewModel = hiltViewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
UserContent(
uiState = uiState,
onRetry = viewModel::loadUser
)
}
@Composable
fun UserContent(
uiState: UserUiState,
onRetry: () -> Unit
) {
Scaffold { padding ->
Box(modifier = Modifier.padding(padding)) {
when {
uiState.isLoading -> CircularProgressIndicator()
uiState.error != null -> ErrorView(uiState.error, onRetry)
uiState.user != null -> UserProfile(uiState.user)
}
}
}
}Examples
示例
Example 1: Type-Safe Navigation
示例1:类型安全导航
Using the new Navigation Compose Type Safety (available in recent versions).
kotlin
// Define Destinations
@Serializable
object Home
@Serializable
data class Profile(val userId: String)
// Setup NavHost
@Composable
fun AppNavHost(navController: NavHostController) {
NavHost(navController, startDestination = Home) {
composable<Home> {
HomeScreen(onNavigateToProfile = { id ->
navController.navigate(Profile(userId = id))
})
}
composable<Profile> { backStackEntry ->
val profile: Profile = backStackEntry.toRoute()
ProfileScreen(userId = profile.userId)
}
}
}使用新版Compose类型安全导航(在近期版本中可用)。
kotlin
// Define Destinations
@Serializable
object Home
@Serializable
data class Profile(val userId: String)
// Setup NavHost
@Composable
fun AppNavHost(navController: NavHostController) {
NavHost(navController, startDestination = Home) {
composable<Home> {
HomeScreen(onNavigateToProfile = { id ->
navController.navigate(Profile(userId = id))
})
}
composable<Profile> { backStackEntry ->
val profile: Profile = backStackEntry.toRoute()
ProfileScreen(userId = profile.userId)
}
}
}Best Practices
最佳实践
- ✅ Do: Use and
rememberto minimize unnecessary calculations during recomposition.derivedStateOf - ✅ Do: Mark data classes used in UI state as or
@Immutableif they contain@Stableor other unstable types to enable smart recomposition skipping.List - ✅ Do: Use for one-off side effects (like showing a Snackbar) triggered by state changes.
LaunchedEffect - ❌ Don't: Perform expensive operations (like sorting a list) directly inside the Composable function body without .
remember - ❌ Don't: Pass instances down to child components. Pass only the data (state) and lambda callbacks (events).
ViewModel
- ✅ 建议: 使用和
remember来减少重组期间不必要的计算。derivedStateOf - ✅ 建议: 如果UI状态中包含或其他不稳定类型,将用于UI状态的数据类标记为
List或@Immutable,以支持智能跳过重组。@Stable - ✅ 建议: 使用处理由状态变化触发的一次性副作用(如显示Snackbar)。
LaunchedEffect - ❌ 禁止: 在无的情况下,直接在可组合函数体中执行昂贵操作(如排序列表)。
remember - ❌ 禁止: 将实例向下传递给子组件。仅传递数据(状态)和Lambda回调(事件)。
ViewModel
Troubleshooting
故障排除
Problem: Infinite Recomposition loop.
Solution: Check if you are creating new object instances (like or ) inside the composition without , or if you are updating state inside the composition phase instead of a side-effect or callback. Use Layout Inspector to debug recomposition counts.
ListModifierremember问题: 无限重组循环。
解决方案: 检查是否在无的情况下在组合内部创建了新的对象实例(如或),或者是否在组合阶段而非副作用或回调中更新状态。使用布局检查器调试重组次数。
rememberListModifier