开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 27 天,点击查看活动详情
Jetpack Compose: 如何调试重组
在这篇帖子中, 我想告诉你我是如何研究Jetsnack中的一个性能问题, 以及我是如何在Jetpack Compose中调试和修复它的.
让我们先看一下Jetsnack的样例.
细节屏幕有一个花哨的折叠工具栏效果, 当我们向上滚动时, 内容会向上移动并调整大小, 而当我们向下滚动时, 内容又会回到它开始的样子.
Jetsnack详情页 — 收起工具条
我们有报告说, 在低端设备上, 当它滚动时, 会显得很不稳定. 因此, 让我们来看看为什么会这样.
Compose阶段总结
不过在我们开始调试之前, 让我们快速浏览一下调试这个问题所需的一些知识. 请记住Compose有3个阶段:
Composition
通过建立一棵Composable树来决定显示什么.Layout
使用该树并确定它们在屏幕上的显示位置.Drawing
在屏幕上绘制可合成物.
Compose三阶段
这里是最酷的部分: 如果一个阶段的状态没有发生变化, 编译可以完全跳过该阶段. 因此, 应该没有必要为了转播屏幕而重新组合. 如果我们能避免改变我们的组成树, 那么Compose将完全跳过组成阶段, 这可以带来性能的提升.
这就是为什么我们的性能文档指出, "当使用频繁变化的状态时, 倾向于使用羔羊修饰符". 使用lambdas是允许工作被推迟到以后的阶段, 并跳过组成阶段的原因.
使用lambda Modifier
为什么使用lambda Modifier意味着我们可以跳过组合? 让我们回到组合树上看看.
改变组合树的Lambda
组合树也是由任何应用于可组合函数的Modifier建立的.
Modifier实际上是不可改变的对象. 当用户向上滚动时, 位置发生变化, Modifier被重建, 旧的Modifier被删除, 新的Modifier被添加到组合树中. 这发生在每次偏移量改变时. 因为构图树发生了变化, 所以会发生重组.
所以请记住, 你不应该为了转述一个屏幕而重新构图,, 尤其是在滚动时, 这会导致粗糙的帧. 每当你看到不必要的重新组合时, 想想如何把工作移到后面的阶段.
修复Jetsnack滚动性能问题
现在我们已经了解了理论, 我们可以深入到Jetsnack中的实际修复.
使用Android Studio中的Layout Inspector, 我们可以看到可组合函数的recomposition counts和skip counts. 如果我们进入Jetsnack的细节页面, 并向上和向下滚动, 可以看到Title可组合函数正在进行大量的重新组合. 很可能在每一帧 😨
注意: 如果你升级到Android Studio Electric Eel, 你也可以在Layout Inspector中看到可组合函数的重组的亮点.
Layout inspector显示重组正在进行
如果我们看一下SnackDetail的可组合函数:
我们可以看到Title读取的是当前的滚动值. 这意味着, 任何时候滚动的变化, 这个可组合的东西都必须被重新组合.
现在看一下Title可组合函数.
它获取滚动值并计算出一个偏移量, 然后这个偏移量被用于graphicLayerModifier来实现屏幕上的位置.
我们可以采取的第一步是将滚动值的读取推迟到Title可组合函数中. 我们可以通过将滚动参数转换为一个lambda来实现.
这将推迟对状态的读取, 并至少将重组的范围限制在只有Title可组合函数. 这很好, 但我们可以做得更好!
正如我们现在所知道的, 在传递频繁变化的状态时, 我们应该更倾向于使用lambda Modifier. 我们的滚动值绝对算得上是频繁变化的!
graphicsLayer
有个lambda版本可以切换. 如果我们用它来代替, 我们可以把读取状态的工作推迟到绘制阶段, 这将意味着可以完全跳过组成. 不过, 仅仅切换到lambda Modifier是不够的. 由于滚动状态仍然在lambda之外被读取以计算偏移量, 我们仍然需要重组.
为了将读取完全推迟到绘制阶段, 我们需要将读取也移到graphicsLayer{ }
Modifier中. 我们将把偏移量的计算移到lambda里面, 看起来像这样.
现在我们的组合状态只在graphicsLayer Modifier内被读取, 我们已经将读取推迟到组合之外, 组合可以被跳过.
如果我们重新运行应用程序并打开Layout Inspector, 我们可以看到组合已经被完全跳过. 没有重新组合, 甚至没有跳过单个可组合函数.
Layout inspector显示没有重组
这就是了! 现在问题解决了, 我们在不使用重组的情况下实现了同样的折叠工具条效果.
更多关于Jetpack Compose的性能提示, 请看我们的性能文档.
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 27 天,点击查看活动详情