之前在 Jetpack Compose 中的重组作用域和性能优化 一文中主要介绍了如何从代码层面进行一些优化以及提到了一些值得注意的优化事项,本文主要来了解一下官方提供了哪些工具层面的手段可以帮助我们进行Compose的debug性能调试。
常规debug方式
这个跟以前的方式一样,先打断点,再Attach Debugger,只不过断点时查看的信息跟以前有所不同
这里有个不友好的点是,在触发断点时的面板中查看的断点信息都是Java的,这样其实不太容易与kotlin代码相对应,对于普通的kotlin代码其实还好,因为官方要全方面的支持kotlin,在调试工具上自然也不会差。但是,对于Compose而言,由于Compose编译器会对Composable代码施加很多魔法,编译产出的java代码和原始kotlin源码可能差异较大,导致实际看到的可能和代码中不太一样。
因此这里如果你尝试去寻找一些跟 Composable 函数相关的有用的信息,可能会比较费劲。
官方也意识到了这一点,于是从 Android Studio Hedgehog | 2023.1.1 (代号:刺猬)开始,对debugger调试器做出了一点改变:当触发断点时,调试器会列出 Composable 函数的参数及其状态,以便开发者能更容易地定位可能导致重组的变化。例如,当你暂停Composable时,调试器可以准确地告诉你哪些参数是“Changed
”或保持“Unchanged
”,这样你就可以更有效地确认导致重组的原因。
可以看到 Recomposition State 下面会列出每个参数和对应状态,以下是参数的状态分类:
- Unchanged State:这个参数没有变化
- Changed:这个参数现在有一个不同的值
- Uncertain:不确定,Compose仍在评估该参数是否发生了变化
- Static:Compose已经确认该参数永远不会变化
- Unstable:该参数是一个不稳定的类型
Layout Inspector(布局检查器)
运行app后,选择Tools > Layout Inspector
界面默认长下面这样:
选中某个组件标签时,面板的左边可以展开对应的 Component Tree,面板的右边可以查看当前组件的属性值等。
注意:如果您没有在布局检查器中看到 Compose 组件,请确保您没有META-INF/androidx.compose.*.version从 APK 中删除文件。这些是布局检查器工作所必需的。
勾选眼睛图标按钮下拉选项Show Borders可以把多余的边框去掉
3D预览
点击右下角的小手下面的图标按钮进入3D预览模式,滑动鼠标可以看到各个视角的效果
效果很酷炫,没什么大的用处,但是对理解布局层次结构还是比较有用的。点击上面的Layer Spacing进度条可以改变不同层次的间距。
隔离布局
如果要查看的布局比较复杂,可以在左侧的 Component Tree 面板中选中某个想要查看的部分,只显示该部分。具体的是右键点击该组件标签,然后选择 Show Only Subtree 或 Show Only Parents。
如需恢复显示完整视图,请右键点击该视图,然后选择 Show All 即可。
Live Updates
如需启用实时布局检查器,请从 Layout Inspector 工具栏中选择 Live Updates 按钮。(需要运行到 API 29+ 的设备或模拟器)
实时布局检查器包含动态布局层次结构,可随着设备上视图的变化更新 Component Tree 和 Layout Display。(实际体验比较卡)
导出和导入布局层次结构快照
快照功能会捕获您在使用布局检查器时通常会看到的数据,包括布局的详细 3D 渲染、视图的组件树、Compose 或混合布局,以及界面中每个组件的详细属性。
如需捕获快照,请点击布局检查器工具栏中的 Export snapshot “导出”图标,请务必以 *.li
扩展名保存文件。导入时,点击 Import snapshot 图标,同样选择*.li
扩展名的文件。
获取重组计数
在调试 Compose 布局时,了解可组合项何时重组对于了解您的 UI 是否已正确实现非常重要。例如,如果重组次数太多,您的应用可能会做不必要的工作。另一方面,如果组件没有按照您的预期进行重组,则可能会导致意外行为。
当您与应用程序交互时,布局检查器会显示可组合项何时重组或跳过。在 Android Studio Flamingo 中,您的重组会突出显示,以帮助您确定可组合项在 UI 中的哪个位置进行重组。
首先,按照下图所示勾选 Show Recomposition Counts
然后,同时需要按照前面提到的开启 Live Updates。
接下来在设备上操作Compose界面就会看到重组计数和跳过重组的计数了:
在 Component Tree中,有两列显示在布局层次结构的旁边。第一列显示每个节点的组合数,第二列显示每个节点的跳过数。
如果觉得某个重组次数比较频繁的组件较为可疑,在Component Tree面板中双击该组件,您将被带到相应的代码处进行分析。
注意:要查看重组计数,请确保您的应用使用的 target API 29 + ,或 Compose 1.2.0更高。
选择可组合节点会显示可组合项的维度和参数,除非它是内联函数,在这种情况下无法显示参数。当选择可组合项时,您还可以在右侧的属性面板中看到类似的信息。
重置计数可以帮助您了解在与您的应用进行特定交互期间的重组或跳过。如果要重置计数,请单击 Component Tree面板顶部附近的 Reset 按钮。
避免 activity 重启
布局检查器需要以下全局设置之一才能正常运行。如果您未指定全局设置,布局检查器会自动进行设置。
-
adb shell settings put global debug_view_attributes_application_package <processname>
此选项会生成用于检查指定进程的额外信息。 -
adb shell settings put global debug_view_attributes 1
此选项会生成用于检查设备上所有进程的额外信息。
更改全局设置可能会导致 activity 重启。如需避免 activity 重启,您可以在 Android Studio 中更改相关设置,或更改设备设置中的开发者选项。
如需在 Android Studio 中启用自动刷新功能,请在菜单中依次选择 Run > Edit Configurations,以打开 Run/Debug Configurations。然后,进入 Miscellaneous 标签页,并勾选 Layout Inspector Options 下的 Connect to Layout Inspector without restarting activity 复选框。
Composition tracing
System Trace 是一款 Android 工具,可将设备活动记录保存到跟踪文件,该文件可提供给定时间段内应用系统进程的整体情况。从 Android Studio Flamingo 开始,您可以使用 Compose Tracing 功能在 System Trace 性能分析器中查看 Compose 函数。 Compose Tracing 可让您获享系统跟踪的低干扰,并获得有关组合的方法跟踪级详细信息,有助于您了解哪些 Compose 函数实际上正在重组。
如需开始使用重组跟踪,您需要至少更新到以下版本:
- Android Studio Flamingo Canary 5
- Compose UI:1.3.0-beta01
- Compose Compiler:1.3.0
- 运行的设备或模拟器必须至少为 API 30。
此外,您还需要新增以下 Compose Runtime Tracing 依赖项:
implementation("androidx.compose.runtime:runtime-tracing:1.0.0-alpha03")
Android 支持两个级别的跟踪:system tracing
和 method tracing
。
-
因为
system tracing
只跟踪专门标记为tracing
的区域,所以它的开销很低,不会对您的应用程序的性能产生太大影响。system tracing
非常适合查看代码的特定部分运行了多长时间。 -
method tracing
跟踪应用程序中的每个函数调用。这是非常昂贵的,因此它会极大地影响您的应用程序的性能,但它可以让您全面了解正在发生的事情、正在调用的函数以及它们被调用的频率。
默认情况下,system tracing
不包括单个可组合函数。它们在method tracing
中可用。但是开启 Compose Tracing后,当您进行包括重组的系统跟踪时,就可以自动在系统跟踪中看到可组合函数。它既利用了system tracing
的低侵入性,也实现了method tracing
中的详细级别。
进行系统跟踪
要获取系统跟踪并查看正在运行的新重组跟踪,请执行以下步骤:
1.打开Profiler:
2.单击CPU 时间轴:
3.选中CPU,选择 System Trace,点击 Record 按钮:
4.到app中操作要进行跟踪的UI界面,然后点击 Stop 按钮:
5.现在应该能够在重组跟踪中看到可组合项。您可以使用键盘(WASD)和鼠标在迹线周围缩放和平移;双击图表中的可组合项会将您转到其源代码。
在AS中查看时,主要查看Threads下面的主轴。
6.您还可以在火焰图中看到可组合项以及文件和行号:
由于AS中的面板较小,看起来不太方便,我们还可以选择将跟踪记录结果右键进行文件导出,然后在 https://ui.perfetto.dev/ 中选择 Open trace file 导入文件进行查看。(这个网站就比较宽敞了,操作起来也方便)
导入之后我们找到我们应用的包名(applicationId), 重点关注Choreographer#doFrame
下面的方块
如果某个Composable横条下面出现了空白很长时间的Gap,说明有人阻塞了Composable的重组调用。
这种情况下可能是因为有大对象或者是某个比较耗时的方法存在:
可以使用trace
对怀疑的地方进行标记:
重新运行后进行系统追踪,发现之前很长的空白Gap果然被怀疑的标记所填充,验证了猜想:
解决方案是使用remember
进行包裹,这样只在首次耗时,后续重组不会每次都重新创建:
当然,你也可以使用Kotlin协程将耗时部分脱离主线程运行。
APK 大小开销
虽然我们的目标是尽可能减少该功能的开销,但由于 Compose 编译器跟踪嵌入到 APK 中的字符串,Compose 应用程序的 APK 大小增加了。如果您的应用程序没有使用太多 Compose 或更大的完整 Compose 应用程序,则此大小增加可能相对较小。这些跟踪字符串还未被混淆,因此它们可以出现在跟踪工具中,如前所示。从 1.3.0 版开始,Compose 编译器将它们注入所有应用程序。
通过添加以下 proguard 规则,可以在生产构建中删除跟踪字符串:
-assumenosideeffects public class androidx.compose.runtime.ComposerKt {boolean isTraceInProgress();void traceEventStart(int,int,int,java.lang.String);void traceEventStart(int,java.lang.String);void traceEventEnd();
}
这些功能将来可能会发生变化,但任何变化都会在 Compose发行说明中提及。
请注意,保留它们虽然会产生一些 APK 大小成本,但可以保证被分析的 APK 与应用程序用户运行的相同。
以上参考自:官网 Composition tracing 介绍 以及 Debugging Jetpack Compose
建议使用最新版本的Android Studio尝试Composition tracing,我目前使用 Flamingo 按照官方要求的配置进行尝试最终未能成功,配置没有问题,但是进行系统追踪生成的tracing记录中却无法到Composable函数的名称。不过官方该项功能也正在实验中,未来应该会有稳定版本。