name: android-jetpack-compose user-invocable: false description: 当使用Jetpack Compose构建Android UI、使用remember/mutableStateOf管理状态或实现声明式UI模式时使用。 allowed-tools:
- Read
- Write
- Edit
- Bash
- Grep
- Glob
Android - Jetpack Compose
用于构建原生Android界面的现代声明式UI工具包。
关键概念
状态管理
Compose提供了几种管理状态的方式:
- remember: 在重组后存活
- rememberSaveable: 在配置更改后存活
- mutableStateOf: 创建可观察状态
- derivedStateOf: 计算状态,当依赖项更改时更新
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Column {
Text("Count: $count")
Button(onClick = { count++ }) {
Text("Increment")
}
}
}
// With saveable for configuration changes
@Composable
fun SearchField() {
var query by rememberSaveable { mutableStateOf("") }
TextField(
value = query,
onValueChange = { query = it },
placeholder = { Text("Search...") }
)
}
状态提升
将状态提升以使组合函数无状态且可重用:
// 无状态组合函数
@Composable
fun NameInput(
name: String,
onNameChange: (String) -> Unit,
modifier: Modifier = Modifier
) {
TextField(
value = name,
onValueChange = onNameChange,
label = { Text("Name") },
modifier = modifier
)
}
// 有状态父组件
@Composable
fun UserForm() {
var name by remember { mutableStateOf("") }
NameInput(
name = name,
onNameChange = { name = it }
)
}
ViewModel集成
class UserViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UserUiState())
val uiState: StateFlow<UserUiState> = _uiState.asStateFlow()
fun updateName(name: String) {
_uiState.update { it.copy(name = name) }
}
fun saveUser() {
viewModelScope.launch {
_uiState.update { it.copy(isLoading = true) }
try {
userRepository.save(_uiState.value.toUser())
_uiState.update { it.copy(isLoading = false, isSaved = true) }
} catch (e: Exception) {
_uiState.update { it.copy(isLoading = false, error = e.message) }
}
}
}
}
@Composable
fun UserScreen(viewModel: UserViewModel = viewModel()) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
UserContent(
uiState = uiState,
onNameChange = viewModel::updateName,
onSave = viewModel::saveUser
)
}
最佳实践
组合函数指南
// 使用Modifier作为第一个可选参数
@Composable
fun CustomCard(
title: String,
modifier: Modifier = Modifier,
onClick: () -> Unit = {}
) {
Card(
modifier = modifier.clickable(onClick = onClick)
) {
Text(
text = title,
modifier = Modifier.padding(16.dp)
)
}
}
// 使用插槽API实现灵活内容
@Composable
fun CustomScaffold(
topBar: @Composable () -> Unit = {},
bottomBar: @Composable () -> Unit = {},
content: @Composable (PaddingValues) -> Unit
) {
Scaffold(
topBar = topBar,
bottomBar = bottomBar,
content = content
)
}
高效重组
// 为列表项使用键
@Composable
fun UserList(users: List<User>) {
LazyColumn {
items(
items = users,
key = { it.id } // 稳定键以实现高效更新
) { user ->
UserItem(user)
}
}
}
// 使用derivedStateOf进行昂贵计算
@Composable
fun FilteredList(items: List<Item>, query: String) {
val filteredItems by remember(items, query) {
derivedStateOf {
items.filter { it.name.contains(query, ignoreCase = true) }
}
}
LazyColumn {
items(filteredItems) { item ->
ItemRow(item)
}
}
}
副作用
// LaunchedEffect用于基于协程的副作用
@Composable
fun UserProfile(userId: String, viewModel: UserViewModel) {
LaunchedEffect(userId) {
viewModel.loadUser(userId)
}
// UI内容
}
// DisposableEffect用于清理
@Composable
fun LifecycleAwareComponent(lifecycle: Lifecycle) {
DisposableEffect(lifecycle) {
val observer = LifecycleEventObserver { _, event ->
// 处理生命周期事件
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}
}
// SideEffect用于非挂起副作用
@Composable
fun AnalyticsScreen(screenName: String) {
SideEffect {
analytics.logScreenView(screenName)
}
}
常见模式
使用Navigation Compose进行导航
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
composable("home") {
HomeScreen(
onNavigateToDetail = { id ->
navController.navigate("detail/$id")
}
)
}
composable(
route = "detail/{itemId}",
arguments = listOf(navArgument("itemId") { type = NavType.StringType })
) { backStackEntry ->
val itemId = backStackEntry.arguments?.getString("itemId")
DetailScreen(itemId = itemId)
}
}
}
Material 3主题
@Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = when {
darkTheme -> darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
else -> lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
)
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}
// 使用主题值
@Composable
fun ThemedCard() {
Card(
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant
)
) {
Text(
text = "Themed content",
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
列表和网格
@Composable
fun ProductGrid(products: List<Product>) {
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 160.dp),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
items(products, key = { it.id }) { product ->
ProductCard(product)
}
}
}
// 粘性头部
@Composable
fun ContactList(contacts: Map<Char, List<Contact>>) {
LazyColumn {
contacts.forEach { (initial, contactsForInitial) ->
stickyHeader {
Text(
text = initial.toString(),
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.surface)
.padding(16.dp),
style = MaterialTheme.typography.titleMedium
)
}
items(contactsForInitial) { contact ->
ContactItem(contact)
}
}
}
}
反模式
避免在组合中执行副作用
错误示例:
@Composable
fun BadExample(viewModel: ViewModel) {
viewModel.loadData() // 每次重组时调用!
Text("Data loaded")
}
正确示例:
@Composable
fun GoodExample(viewModel: ViewModel) {
LaunchedEffect(Unit) {
viewModel.loadData()
}
Text("Data loaded")
}
不要在Remember块中读取状态
错误示例:
@Composable
fun BadCounter(initial: Int) {
// 当初始值更改时不会更新
var count by remember { mutableStateOf(initial) }
}
正确示例:
@Composable
fun GoodCounter(initial: Int) {
var count by remember(initial) { mutableStateOf(initial) }
}
避免在组合期间进行繁重计算
错误示例:
@Composable
fun BadList(items: List<Item>) {
// 每次重组时运行
val sorted = items.sortedBy { it.name }
LazyColumn { /* ... */ }
}
正确示例:
@Composable
fun GoodList(items: List<Item>) {
val sorted by remember(items) {
derivedStateOf { items.sortedBy { it.name } }
}
LazyColumn { /* ... */ }
}
相关技能
- android-architecture: MVVM和清洁架构模式
- android-kotlin-coroutines: Compose中的异步操作