Jetpack Compose :使用 derivedStateOf 优化重组
Jetpack Compose中的derivedStateOf可以优化重组性能,避免不必要的重复计算。本文通过邮箱验证示例说明:当状态变化触发重组时,直接计算表达式会导致每次重组都重新执行逻辑。而使用derivedStateOf包裹计算逻辑后,Compose会缓存结果,仅在依赖的状态(如email)变化时才重新计算。文章深入解析了其内部原理:通过DerivedSnapshotState跟踪依赖项并
引言
在 Jetpack Compose 重组中可能会包含逻辑,要是逻辑简单,可能没啥影响;可要是逻辑计算成本高,不知不觉就会拖慢 App 性能。 本篇文章就来讲讲如何用 derivedStateOf
帮你优化这类情况。你会看到它如何自动缓存派生逻辑的结果,只有真正依赖项变了,才会重新计算。
问题:举个代码例子理解
假设你要验证邮箱逻辑,在 TextField 输入内容时触发验证:
val isValid = email.endsWith("@gmail.com")
然后在 Composable 函数里调用,像这样:
@Composable
fun EmailValidator() {
var email by remember { mutableStateOf("") }
val isValid = email.endsWith("@gmail.com")
}
每次输入时(比如输入 richa
、richa.sharma
、richa.sharma@gmail
),都会触发重组,endsWith
方法也会每次重新执行。这逻辑看着小,可要是换成复杂正则或解析逻辑呢?因为这些表达式就在 @Composable
函数里,Compose 不会记住之前结果,每次都得重新算整个代码块。
问题就在于“没必要的重复计算”。不是每次重组都会改变计算的输入,但 Compose 还是会执行,原因是:
- 它会重新调用
@Composable
函数。 - 会重新计算所有表达式。
解决方案:用 derivedStateOf
修改代码,用 derivedStateOf
:
val isValid by remember {
derivedStateOf {
email.endsWith("@gmail.com")
}
}
Compose 会跟踪 email
。只有 email
变了,才会重新计算 isValid
。要是因为其他原因(比如主题变化、无关状态改变)导致 UI 重组,验证逻辑也不会重新计算。
深入理解 Compose 内部原理
我们在 remember { ... }
里用 derivedStateOf
,remember
能在重组时保留代码块的结果。
derivedStateOf
的函数签名是这样:
fun <T> derivedStateOf(calculation: () -> T): State<T>
derivedStateOf
会创建一个特殊的 State
对象(技术上是 DerivedState<T>
),它的作用:
- 包含计算逻辑(这里就是
email.endsWith(...)
)。 - 跟踪输入依赖。
remember
能保证未来重组时,同一个 DerivedSnapshotState
被复用,不会重新创建,也不会丢失缓存值。
DerivedSnapshotState
是个特殊的内部类,功能如下:
- 实现
State<T>
,所以有.value
属性。 - 缓存最后一次计算的结果。
- 跟踪 lambda 里读取了哪些
state
对象。 - 知道啥时候该让缓存失效。
内部工作流程拆解
val isValid = derivedState.value
上面代码中 DerivedSnapshotState
的 value
获取逻辑大概这样(伪代码示意):
override val value: T
get() {
if (currentValue is valid) {
return currentValue
} else {
// 执行计算逻辑(比如 email.endsWith(...) )
// 跟踪 lambda 里读了哪些 State 对象
// 把结果存起来,下次用
return newValue
}
}
要是缓存值有效,直接返回,不重复计算。 要是缓存失效:
- 执行 lambda,比如
email.endsWith("@gmail.com")
。 - 记录读取了
email
这个状态。 - 存储计算结果。
- 返回新结果。
当 email
变化时,Compose 知道 lambda 里读了 email
,就会把派生状态标记为“失效”。下次读 .value
时,就会用新的 email
重新执行 lambda。
要是 email
没变化,却因为其他原因触发重组,就会复用缓存值,不用重新计算——效率更高!
总结:derivedStateOf 的意义
derivedStateOf
是 Compose 实现“记忆化计算”的方式,只有依赖的状态变了,才会重新计算,不是每次重组都算。
它是你控制 Compposable 里“昂贵/没必要的重复计算”的工具。不会阻止重组,但能让派生值 只在真正依赖项变化时 重新计算,而非 UI 每次有小更新都算。
下次写验证、筛选、复杂正则,或者其他派生值逻辑时,停一停,问问自己:
- 这逻辑需要每次重组都执行吗?
- 能不能用
derivedStateOf
包一下,提升效率?
只需加一点代码,就能让 Compose UI 更快、更高效、更可预测——这正是现代 Android 应用需要的!
更多推荐
所有评论(0)