本文不重复基础入门,而是围绕状态管理和性能优化两大工程痛点,结合完整代码示例,带你深入 Compose 的生产级实践。
remember 到状态提升在 Compose 中,状态通过 mutableStateOf 创建,配合 remember 在重组间保留。以下是一个简单的计数器示例:
@Composable
fun Counter() {
// remember 确保状态在重组后不被重置
var count by remember { mutableStateOf(0) }
Column {
Text("点击次数: $count")
Button(onClick = { count++ }) {
Text("增加")
}
}
}然而,当状态需要被多个可组合函数共享或在 Activity 生命周期中存活时,单纯使用 remember 是不够的——它只存在于当前组合中,配置变更(如屏幕旋转)会丢失数据。此时应使用 rememberSaveable 或引入 ViewModel。
状态提升(State Hoisting) 是 Compose 的核心设计模式:将状态上移至调用方,使可组合函数变为无状态(Stateless),更易于测试和复用:
// 无状态的可组合项:状态由父级管理
@Composable
fun StatelessCounter(
count: Int,
onIncrement: () -> Unit,
modifier: Modifier = Modifier
) {
Column(modifier = modifier) {
Text("点击次数: $count")
Button(onClick = onIncrement) {
Text("增加")
}
}
}对于复杂屏幕,推荐使用 ViewModel + StateFlow 作为状态容器,实现单向数据流。以下是一个实时搜索过滤的完整示例:
// ViewModel:持有状态与业务逻辑
class FilterViewModel : ViewModel() {
private val allItems = listOf("Cupcake", "Donut", "Eclair", "Froyo")
private val _filteredItems = MutableStateFlow(allItems)
val filteredItems: StateFlow<List<String>> = _filteredItems.asStateFlow()
fun filter(query: String) {
_filteredItems.value = if (query.isEmpty()) {
allItems
} else {
allItems.filter { it.contains(query, ignoreCase = true) }
}
}
}
// Composable 中收集状态
@Composable
fun SearchScreen(viewModel: FilterViewModel = viewModel()) {
val filteredItems by viewModel.filteredItems.collectAsStateWithLifecycle()
var query by rememberSaveable { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
OutlinedTextField(
value = query,
onValueChange = {
query = it
viewModel.filter(it) // 触发过滤逻辑
},
label = { Text("搜索") }
)
LazyColumn {
items(filteredItems, key = { it }) { item ->
Text(item, modifier = Modifier.padding(8.dp))
}
}
}
}collectAsStateWithLifecycle() 是 Android 官方推荐的 API,它会感知生命周期,在屏幕不可见时停止收集,节省资源。
Composable 函数应是纯函数,不应直接执行网络请求或数据库操作。Compose 提供了多种副作用 API:
LaunchedEffect:在组合进入时启动协程,离开时自动取消。DisposableEffect:需要清理资源时使用(如注册监听器)。rememberCoroutineScope:获取协程作用域,在回调中启动协程。@Composable
fun UserProfile(userId: String) {
var user by remember { mutableStateOf<User?>(null) }
// 当 userId 变化时重新执行
LaunchedEffect(userId) {
user = fetchUserFromApi(userId) // 挂起函数
}
user?.let { Text("用户名: ${it.name}") } ?: CircularProgressIndicator()
}重组是 Compose 更新 UI 的机制,但无效重组会导致卡顿。优化需聚焦三个核心点。
key 参数LazyColumn 未指定 key 时,Compose 默认按位置索引识别条目,列表头部插入新数据会触发全量重组。正确做法是使用唯一稳定的 ID:
LazyColumn {
items(users, key = { it.id }) { user -> // it.id 为 Long 类型
UserItem(user)
}
}注意 key 必须是可序列化到 Bundle 的类型(Int、Long、String 等)。
Compose 编译器会判断参数类型是否“稳定”,不稳定类型会导致无法跳过重组。例如,data class User(val id: Long, val name: String, val tags: List<String>) 中的 List<String> 是不稳定类型。
解决方案有两种:
kotlinx.collections.immutable.ImmutableList@Immutable 显式标注,承诺属性创建后不变@Immutable
data class User(
val id: Long,
val name: String,
val tags: List<String> // 承诺不会在外部修改
)derivedStateOf 减少不必要的重组当状态变化频率高于 UI 更新需求时,使用 derivedStateOf 隔离计算:
val list = remember { mutableStateListOf(1, 2, 3) }
// 只有 count > 0 变化时才触发重组,而非每次 list 增删都触发
val hasItems by remember { derivedStateOf { list.isNotEmpty() } }Compose 的 Animatable 是处理手势动画的核心 API,支持与触摸事件同步。以下是一个“滑动删除”修饰符的核心实现:
fun Modifier.swipeToDismiss(onDismissed: () -> Unit): Modifier = composed {
val offsetX = remember { Animatable(0f) }
this.pointerInput(Unit) {
val decay = splineBasedDecay<Float>(this)
coroutineScope {
while (true) {
val velocityTracker = VelocityTracker()
// 停止正在运行的动画
offsetX.stop()
val pointerId = awaitPointerEventScope { awaitFirstDown().id }
horizontalDrag(pointerId) { change ->
launch {
offsetX.snapTo(offsetX.value + change.positionChange().x)
}
velocityTracker.addPosition(change.uptimeMillis, change.position)
}
// 判断是否滑动超过阈值,执行删除或回弹
val velocity = velocityTracker.calculateVelocity().x
val target = if (offsetX.value < -200f) {
onDismissed()
-1000f
} else 0f
launch { offsetX.animateTo(target, spring()) }
}
}
}
}Jetpack Compose 的核心优势在于将 UI 声明为状态的函数,通过 State、ViewModel、副作用 API 和 性能优化工具 构建了一套完整的响应式 UI 框架。生产项目中,建议遵循以下原则:
LazyColumn 配置稳定的 key@Immutable 标注数据类,提升重组跳过率Compose 不是简单的“去掉 XML”,而是一种全新的 UI 编程范式。掌握其状态驱动模型与性能调优手段,是迈向现代 Android 开发的关键一步。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。