重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
android-jetpack-compose-expert by sickn33/antigravity-awesome-skills
npx skills add https://github.com/sickn33/antigravity-awesome-skills --skill android-jetpack-compose-expert一份使用 Jetpack Compose 构建生产级质量 Android 应用程序的全面指南。此技能涵盖架构模式、使用 ViewModel 的状态管理、类型安全的导航以及性能优化技术。
确保你的 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" }
使用带有 的 来暴露 UI 状态。避免暴露 。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
StateFlowViewModelMutableStateFlow// 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) }
}
}
}
}
在"屏幕"可组合项中使用状态,并将数据传递给无状态组件。
@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 类型安全功能(在较新版本中可用)。
// 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 来最小化重组期间不必要的计算。List 或其他不稳定类型,请将其标记为 @Immutable 或 @Stable,以启用智能重组跳过。LaunchedEffect 来处理由状态变化触发的一次性副作用(例如显示 Snackbar)。remember 的情况下,直接在可组合函数体内执行昂贵的操作(如对列表排序)。ViewModel 实例向下传递给子组件。只传递数据(状态)和 lambda 回调(事件)。问题: 无限重组循环。解决方案: 检查你是否在没有 remember 的情况下在组合内部创建了新的对象实例(如 List 或 Modifier),或者你是否在组合阶段(而非副作用或回调中)更新了状态。使用布局检查器来调试重组次数。
每周安装量
65
代码仓库
GitHub 星标数
27.4K
首次出现
2026年2月24日
安全审计
已安装于
codex63
opencode63
amp62
github-copilot62
kimi-cli62
gemini-cli62
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.
Ensure your libs.versions.toml includes the necessary Compose BOM and libraries.
[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" }
Use ViewModel with StateFlow to expose UI state. Avoid exposing 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) }
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) }
}
}
}
}
Consume the state in a "Screen" composable and pass data down to stateless components.
@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)
}
}
}
}
Using the new Navigation Compose Type Safety (available in recent versions).
// 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 and derivedStateOf to minimize unnecessary calculations during recomposition.@Immutable or @Stable if they contain List or other unstable types to enable smart recomposition skipping.LaunchedEffect for one-off side effects (like showing a Snackbar) triggered by state changes.remember.ViewModel instances down to child components. Pass only the data (state) and lambda callbacks (events).Problem: Infinite Recomposition loop. Solution: Check if you are creating new object instances (like List or Modifier) inside the composition without remember, or if you are updating state inside the composition phase instead of a side-effect or callback. Use Layout Inspector to debug recomposition counts.
Weekly Installs
65
Repository
GitHub Stars
27.4K
First Seen
Feb 24, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex63
opencode63
amp62
github-copilot62
kimi-cli62
gemini-cli62
Kotlin Exposed ORM 模式指南:DSL查询、DAO、事务管理与生产配置
1,100 周安装
如何撰写技术博客文章:tldraw官方写作流程与SEO优化指南
100 周安装
FastAPI 后端模板 | Python FastAPI + PostgreSQL + SQLAlchemy 2.0 异步开发框架
100 周安装
Base技能包:bankrbot开源AI助手核心技能库,提升开发效率与代码质量
99 周安装
Yoink链上夺旗游戏:Base链智能合约交互指南与玩法规则
99 周安装
Godot MCP 场景构建器 - 高级智能体接口,从零构建 Godot 游戏场景
102 周安装
构建完整AI聊天应用指南:Next.js + Neon + AI SDK实现持久化聊天与自动命名
100 周安装