强制跳过是 Compose 编译器中提供的一种模式。启用后,它会通过以下两种方式更改编译器的行为:
启用强力跳过模式
Kotlin 2.0.20 中默认启用强制跳过功能。
如需在 2.0.20 之前的版本中为 Gradle 模块启用强制跳过功能,请在 Gradle 配置的 composeCompiler
块中添加以下选项:
android { ... }
composeCompiler {
enableStrongSkippingMode = true
}
可组合项的可跳过性
强制跳过模式会放宽 Compose 编译器通常在跳过和可组合函数方面应用的一些稳定性规则。默认情况下,如果可组合函数的所有参数都具有稳定的值,Compose 编译器会将其标记为可跳过。强力跳过模式会改变这一点。
启用强制跳过后,所有可重启的可组合函数都将变为可跳过。无论这些广告系列是否包含不稳定的参数,都适用此规则。不可重启的可组合函数仍然无法跳过。
何时跳过
为了确定是否要在重新组合期间跳过某个可组合项,Compose 会将每个参数的值与其之前的值进行比较。比较类型取决于参数的稳定性。
- 不稳定参数是使用实例是否相等 (
===
) 进行比较 - 系统使用对象相等性 (
Object.equals()
) 比较稳定参数
如果所有参数都满足这些要求,Compose 会在重组期间跳过该可组合项。
您可能希望可组合项停用强制跳过功能。也就是说,您可能需要一个可重启但不可跳过的可组合项。在这种情况下,请使用 @NonSkippableComposable
注解。
@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}
将类标记为稳定
如果您希望对象使用对象等式(而非实例等式),请继续使用 @Stable
为给定类添加注解。例如,在观察整个对象列表时,Room 等数据源会在列表中的某个项发生变化时为列表中的每个项分配新的对象。
Lambda 记忆化
强力跳过模式还支持对可组合项内的 lambda 进行更多记忆化。启用强力跳过后,系统会自动记住可组合函数内的每个 lambda。
示例
为了在使用强制跳过时实现对可组合项中的 lambda 进行 memoization,编译器会使用 remember
调用封装您的 lambda。其键是 lambda 的捕获。
假设您有一个 lambda,如以下示例所示:
@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
val lambda = {
use(unstableObject)
use(stableObject)
}
}
启用强力跳过后,编译器会通过将 lambda 封装在 remember
调用中来对其进行 memoization:
@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
val lambda = remember(unstableObject, stableObject) {
{
use(unstableObject)
use(stableObject)
}
}
}
键遵循与可组合函数相同的比较规则。运行时使用实例相等性比较不稳定的键。它使用对象等式比较稳定键。
记忆化和重组
这项优化大大增加了运行时在重组期间跳过的可组合项的数量。如果不进行 memoization,运行时更有可能在重组期间向接受 lambda 参数的任何可组合项分配新的 lambda。因此,新 lambda 的参数与上一个组合不等。这会导致重新组合。
避免 memoization
如果您不想对某个 lambda 进行 memoization,请使用 @DontMemoize
注解。
val lambda = @DontMemoize {
...
}
APK 大小
在编译时,与不可跳过的可组合项相比,可跳过的可组合项会生成更多代码。启用强制跳过后,编译器会将几乎所有可组合项标记为可跳过,并将所有 lambda 封装在 remember{...}
中。因此,启用强力跳过模式对应用的 APK 大小影响非常小。
在现在用 Android 中启用强制跳过功能会使 APK 大小增加 4KB。大小差异在很大程度上取决于给定应用中之前不可跳过的可组合项的数量,但应该相对较小。