Compose Performance Review

Compose Performance Review

Compose 性能提升的关键

很多初学者在刚接触 Compose 时可能会感到迷惑,不知道 compose 性能优化的重点在哪里。今天我们尝试从一个点出发,逐步分析如何编写高性能的 Compose UI。

关键词:重组。影响 Compose 性能最大的就是重组,所有的性能优化都应从重组开始分析。

为什么会重组?

我们先把复杂的问题简单化,然后逐步分析,再网络化记忆这些知识点。

  1. 状态(state)变化导致重组
  2. 可组合函数(composable function)的输入发生变化

上面两点写得很简单,没关系,我们一步步分析其中的道理。

如何降低状态变化导致的重组

状态变化导致重组的原理

具体原理见这篇文章

如何减少状态变化导致的重组?

降低状态变化的频率

如何降低状态变化的频率呢?

  1. 使用 Compose 的 derivedStateOf 来限制、降低状态变化的频率,以减少无效重组。
  2. 使用 Kotlin Flow 的 distinctUntilChanged 来降低重复数据流。
减少状态读取的范围

使用 defer read 的方式来降低状态影响的范围。所谓 defer read 就是通过将状态传入 lambda,然后传递给使用的地方,从而减少重组。为什么放到 lambda 里面可以降低重组?我们后面会详细讨论。

如何降低输入变化导致的重组?

先看一段代码:

kotlin 复制代码
@Composable
fun CustomText(
    text: String,
    modifier: Modifier = Modifier.padding(top = 46.dp),
) {
    Text(
        text = text,
        modifier = modifier.padding(32.dp),
        style = TextStyle(
            fontSize = 20.sp,
            textDecoration = TextDecoration.Underline,
            fontFamily = FontFamily.Monospace
        )
    )
}
java 复制代码
public static final void CustomText(@NotNull String text, @Nullable Modifier modifier, @Nullable Composer $composer, int $changed, int var4) {
   Intrinsics.checkNotNullParameter(text, "text");
   $composer = $composer.startRestartGroup(-837456306);
   ComposerKt.sourceInformation($composer, "C(CustomText)P(1)95@3325L244:Donout.kt#fvbk59");
   int $dirty = $changed;
   if ((var4 & 1) != 0) {
      $dirty = $changed | 6;
   } else if (($changed & 6) == 0) {
      $dirty = $changed | ($composer.changed(text) ? 4 : 2);
   }

   if ((var4 & 2) != 0) {
      $dirty |= 48;
   } else if (($changed & 48) == 0) {
      $dirty |= $composer.changed(modifier) ? 32 : 16;
   }

   if (($dirty & 19) == 18 && $composer.getSkipping()) {
      $composer.skipToGroupEnd();
   } else {

通过编译后的代码,我们可以看到 Compose 方法在进入重组时,会有一个标志字段 $dirty 通过位运算 来计算当前代码是否可以跳过。代码中有两处 $composer.changed(text)$composer.changed(modifier),通过 composer 调用 changed 方法来判断入参是否改变。

changed 方法源码在这里可见,感兴趣的可以看下。方法逻辑比较清晰,changed 方法有几个重要规则:

  1. 对基本类型(Int, String 等)使用值相等比较
  2. 对非稳定类型(如普通 class)使用引用相等比较
  3. 对声明为 @Stable 的类或 data class 会启用结构相等比较

了解了规则后,我们的优化方向就明确了。对于基本类型,Compose 的编译器直接使用 equality,对于 @Stable 注解的类也会直接使用等值比较。除了 @Stable@Immutable 注解的类型,Compose 里面有多少稳定类型?

  • 所有基元值类型:BooleanIntLongFloatChar 等。
  • 字符串
  • 所有函数类型(lambda)

当然 lambda 在没有开启强跳模式情况下,对于返回值不是 Unit 的类型,还是会被判断成不稳定类型,因为返回值可能会改变,从而导致重组。

了解了上面的稳定性规则后,我们可以在日常开发中尽量使用 Kotlin 的不可变类型作为入参,以减少重组次数。

使用 remember 系列减少重组的负载压力

在降低了重组次数后,还有没有其他方式能够降低重组的压力呢?Compose 提供了一个特别的操作------使用 remember 来减少重组过程的计算,避免多次无用的计算。

总结

回顾一下本篇内容,所有关于 Compose 的性能优化都是从重组开始分析的。一个是降低重组频率,重组频率从 state 和 stability 两个方面分析并进行优化;另一个是使用 Compose 里面的 remember 进行缓存,减少多次重复计算的压力。

相关推荐
蓝天下小溪旁戴着耳机去放羊12 小时前
详解数据传输——零拷贝、direct IO
性能优化·操作系统
Python数据分析与机器学习18 小时前
《基于锂离子电池放电时间常数的自动化电量评估系统设计》k开题报告
运维·性能优化·自动化·软件工程·软件构建·个人开发
weixin_748877001 天前
【2025年后端开发终极指南:云原生、AI融合与性能优化实战】
人工智能·云原生·性能优化
NoneCoder1 天前
工程化与框架系列(22)--前端性能优化(中)
前端·性能优化·状态模式
大模型铲屎官1 天前
Python 性能优化:从入门到精通的实用指南
开发语言·人工智能·pytorch·python·性能优化·llm·编程
Wgllss1 天前
该怎么学Android进阶,拒绝沦为高级三方SDK调用工程师?
android·架构·android jetpack
勤劳打代码2 天前
烽火连营——爆杀 Jank 闪烁卡顿
flutter·面试·性能优化
eason_fan2 天前
你知道src和srcset的加载顺序吗?
前端·性能优化·html
helson赵子健2 天前
《Android性能优化之道》——从底层原理到一线实践
android·面试·性能优化