Android Jetpack Compose 专家

android-jetpack-compose-expert
分类设计
作者Agentic Awesome Skills 社区
许可MIT
评分4.80/5
使用15.6K

Android Jetpack Compose 专家

概述

本指南旨在帮助开发者使用 Jetpack Compose 构建生产级 Android 应用程序。涵盖的内容包括架构模式、基于 ViewModel 的状态管理、类型安全的导航以及性能优化技术。

适用场景

  • 启动使用 Jetpack Compose 的新 Android 项目时。
  • 将传统的 XML 布局迁移到 Compose 时。
  • 实现复杂的 UI 状态管理和副作用(Side Effects)时。
  • 优化 Compose 性能(如重组次数、稳定性)时。
  • 配置类型安全的导航(Navigation)时。

分步指南

1. 项目设置与依赖

确保你的 libs.versions.toml 包含了必要的 Compose BOM 和相关库。

kotlin
[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. 状态管理模式 (MVI/MVVM)

使用 ViewModel 配合 StateFlow 来暴露 UI 状态。避免直接暴露 MutableStateFlow

kotlin
// UI 状态定义
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. 创建 Screen Composable

在“Screen”级 Composable 中消费状态,并将数据向下传递给无状态(Stateless)组件。

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)
}
}
}
}

示例

示例 1:类型安全导航

使用最新的 Navigation Compose 类型安全特性
(在最新版本中可用)。

kotlin
// 定义目的地
@Serializable
object Home

@Serializable
data class Profile(val userId: String)

// 配置 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)
}
}
}

最佳实践

  • 建议: 使用 rememberderivedStateOf 来减少重组期间不必要的计算。
  • 建议: 如果 UI 状态中使用的 data class 包含 List 或其他不稳定类型,请将其标记为 @Immutable@Stable,以启用智能重组跳过。
  • 建议: 对于由状态变化触发的一次性副作用(如显示 Snackbar),请使用 LaunchedEffect
  • 避免: 在 Composable 函数体中直接执行昂贵的操作(如对列表进行排序)而没有使用 remember
  • 避免:ViewModel 实例向下传递给子组件。仅传递数据(状态)和 lambda 回调(事件)。

故障排除

问题: 无限重组循环。
解决方案: 检查是否在 composition 过程中创建了新的对象实例(如 ListModifier)而未使用 remember,或者是否在 composition 阶段而非副作用或回调中更新了状态。使用 Layout Inspector 来调试重组次数。

局限性

  • 仅在任务明确符合上述范围时使用此技能。
  • 不要将输出结果视为环境特定验证、测试或专家评审的替代方案。
  • 如果缺少必要的输入、权限、安全边界或成功标准,请停止并请求澄清。