mcpField
A
android-jetpack-compose-expert

android-jetpack-compose-expert

github.com/sickn33开发48.7k227 次安装今天更新
代码仓库

关于 android-jetpack-compose-expert

面向 Android 开发者的 Jetpack Compose 开发指导技能,涵盖架构、状态管理、导航和性能优化,适用于新建项目及 XML 布局迁移。

主要功能

  1. 01使用 ViewModel 与 StateFlow 管理状态
  2. 02MVI 和 MVVM 模式指导
  3. 03类型安全的 Navigation Compose
  4. 04重组性能优化建议
  5. 05副作用处理实践

适用场景

  1. 01启动 Jetpack Compose 应用
  2. 02将 XML 布局迁移到 Compose
  3. 03管理 UI 状态与副作用
  4. 04排查重组性能问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill android-jetpack-compose-expert

安装后在 Claude Code 中输入/android-jetpack-compose-expert确认已加载。

详细介绍

Android Jetpack Compose 专家

概述

这是一份全面指南,介绍如何使用 Jetpack Compose 构建可用于生产环境的 Android 应用。本技能涵盖架构模式、使用 ViewModel 管理状态、类型安全的导航以及性能优化技巧。

适用场景

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

分步指南

1. 项目设置与依赖项

确保 libs.versions.toml 包含必需的 Compose BOM 和库。

[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。

// 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, error = null) }
            try {
                val user = userRepository.getUser()
                _uiState.update { it.copy(user = user, isLoading = false) }
            } catch (e: kotlinx.coroutines.CancellationException) {
                throw e
            } catch (e: Exception) {
                _uiState.update { it.copy(error = e.message, isLoading = false) }
            }
        }
    }
}
3. 创建 Screen Composable

在 “Screen” Composable 中使用状态,并将数据传递给无状态组件。

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

上面的依赖项版本是历史示例,并非当前推荐的技术栈。类型安全导航还需要兼容的 Navigation Compose、Kotlin 序列化插件和依赖项;生命周期状态收集和 Hilt 需要各自的依赖项、导入和设置。Fragment 需要项目中的 User/Repository/View 组件。请有意触发初始加载(例如在 ViewModel init 中或通过带键的 effect);仅调用 onRetry 不会加载第一个 user。避免加载任务重叠,也不要在 UI 中暴露原始服务器异常消息。

示例

示例 1:类型安全导航

使用新版 Navigation Compose 类型安全功能(近期版本提供)。

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

最佳实践

  • ✅ 应该: 使用 remember 和 derivedStateOf,尽量减少重组期间不必要的计算。
  • ✅ 应该: 仅在类型确实遵守相应约定时才使用 @Immutable/@Stable;不要通过给可变集合添加注解来掩盖不稳定性。优先使用不可变数据,并检查编译器报告(Android 指南)。
  • ✅ 应该: 使用 LaunchedEffect 处理由状态变化触发的一次性副作用(例如显示 Snackbar)。
  • ❌ 不要: 不使用 remember 就直接在 Composable 函数体内执行耗时操作(例如排序列表)。
  • ❌ 不要: 将 ViewModel 实例传递给子组件。只传递数据(状态)和 lambda 回调(事件)。

故障排除

问题: 无限重组循环。 解决方案: 仅创建新对象并不会导致无限循环。检查是否在组合阶段更新了被观察的状态,从而形成反馈循环;这类更新应放在副作用或回调中。使用 Layout Inspector 调试重组次数。

限制

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

评论

支持 Markdown