2. 调试工具链概览:常用工具与选择归纳

做 Compose 开发,最头疼的不是写代码,而是出了问题不知道怎么查。我刚开始从 View 系统切到 Compose 时,就栽过跟头。那时布局死活不对,我拿着 Android Studio 的 Layout Inspector 看了半天,愣是找不到原因。后来才发现,那会儿的 Layout Inspector 对 Compose 支持还很弱。

工具这东西,选对了省一半力。但前提是——你得知道它们各自能干什么。

核心观点:没有一把万能钥匙。Compose 调试需要组合使用多款工具,对症下药。

2.1 工具全景图

我习惯把 Compose 调试工具分成五类:

  • 日志与分析工具——Logcat 和 Android Profiler,用来抓崩溃、卡顿和内存泄漏
  • UI 与布局工具——Layout Inspector 和 Compose UI Checker,查界面层级和测量行为
  • 重组追踪工具——Recomposition Counts 和 Compose Compiler Metrics,分析性能瓶颈
  • 状态与调试工具——Debugger、Breakpoints 和 State Inspector,定位数据流问题
  • 专项检测工具——StrictMode、Baseline Profiles Device Dump 及应用内工具面板

下面这张图是我自己画的一个工具选择框架。你想想看,遇到问题先定位类型,再选工具,逻辑会清晰很多。

Compose调试工具选择框架 Compose 问题排查入口 性能问题 UI/布局问题 状态/数据流问题 卡顿/掉帧 重组过多 布局错位 测量异常 手势冲突 状态不同步 内存泄漏 异步错误 Logcat/Profiler 重组计数器 Layout Inspector Compose Inspector 手势检测工具 State Inspector LeakCanary Debugger/Breakpoints 使用建议 1. 先定位问题类型,再选择对应工具集 2. 多数情况下,至少需要组合 2~3 款工具协同排查 3. 别忘了开启 Compose Compiler Metrics,它能告诉你重组详情 4. 工具本身也是排查对象,版本不对会导致误判

2.2 各个工具的战场

2.2.1 性能调优组

Logcat + Android Profiler——这事老搭档了。遇到崩溃、ANR 和掉帧,它们永远是第一选择。我有个习惯,排查卡顿前会先在 Logcat 里搜一下 Choreographer 关键字。

# 常用的 Logcat 过滤命令
# 卡顿监测
adb logcat -s Choreographer:I

# 重组信息
adb logcat -s Compose:V

# 强制开启布局边界
adb shell setprop debug.layout true
adb shell setprop persist.debug.layout true

Android Profiler 里的 CPU Profiler 对 Compose 来说尤其重要。你可以看到布局阶段和重组阶段具体耗时。我记得有一次排查一个 LazyColumn 滑动卡顿问题,就是在 CPU Profiler 里发现 Modifier.drawWithContent 被重复调了上千次。

技巧:在 Profiler 中,留意 "Compose" 标签下的系统调用。如果某个 Composable 函数的调用次数远高于预期,那大概率是发生了「无意义重组」。

2.2.2 UI 与布局检查组

Layout Inspector——嗯,这工具从 View 时代就在用。在 Compose 里,它只能帮你看到最终渲染出来的节点层级。说白了,它适合用来查「东西出来没有」、有没有被裁剪、层级是否异常。

Compose UI Checker(应用内面板 + 开发者选项)——这才是真正为 Compose 设计的工具。它能实时显示每个 Composable 的重组次数、跳过次数和耗时。

// 在 build.gradle.kts 中开启 Compose Compiler 统计信息
composeCompiler {
    reportsDestination = layout.buildDirectory.dir("compose-reports")
    metricsDestination = layout.buildDirectory.dir("compose-metrics")
}

你运行完编译后,会在相应目录生成一份 compose-reports 文件。里面有每个函数的重组状态标记——restartable、skippable、lambda。我看到很多团队新人拿到这份报告完全看不懂,其实核心就三点:

  • restartable:该函数可以被系统重新调用(不是坏事)
  • skippable:该函数在输入参数不变时可以跳过渲染(这是好事)
  • lambda:表示函数的尾 lambda 改变可能导致重组(需要留意捕获的作用域)

2.2.3 状态调试三件套

Debugger + Breakpoints + Evaluate Expression——我在 Zustand 调试时最常用的组合。不过有一点你千万要注意:在 Compose 的 Lambda 中使用断点,可能被 inline 机制影响,导致跳转逻辑不对。碰到这种情况,我一般会在对应状态变量上打一个条件断点。

State Inspector——它其实是 Android Studio 里的一个实验功能。能直接显示当前 Composable 树中所有的 MutableState 对象及其值。说白了,你可以在运行时看到一个实时刷新的状态表。

注意:State Inspector 只在 Debug 模式下可用,而且需要修改 gradle.properties:
android.experimental.enableStateInspector=true
否则点了也没反应。

2.2.4 专项检测工具

工具 检测目标 我的建议
StrictMode 主线程磁盘IO、网络、慢SQL 建议在 Debug 中全程开启
LeakCanary Composable 持有的 Activity/Context 泄漏 尤其要检查在 remember 外部的匿名内部类
Baseline Profiles 首次安装后的预热性能 生成后放到设备上测启动速度
Compose Compiler Metrics 细粒度重组统计 开启后导出到本地分析
应用内工具面板(自定义) 业务层状态快照、网络延迟模拟 我习惯单独做一个 Compose 调试浮窗

2.3 选择的逻辑:用三句话讲明白

我个人给出了一个简单的决策模型。拿不准用哪个工具时,问自己三个问题:

  1. 这个问题能不能复现?——能,用 Debugger + Inspector;不能,上 Logcat + Profiler 捕捉痕迹。
  2. 跟布局尺寸有关,还是跟性能有关?——布局错位用 Layout Inspector;掉帧卡顿用 Profiler + 重组计数器。
  3. 有没有涉及状态缓存或异步逻辑?——有,就开启 State Inspector 和条件断点。
避坑指南:我曾经犯过一个低级错误——用 Layout Inspector 去检查 3D 变换后的组件。Layout Inspector 的截图是静态的,它根本看不见变换后内容。白白查了半天。

后来我才想起来,应该用 MemInfo + GPU 渲染模式来辅助确认。所以有些时候,工具选择错了,方向直接偏了。

2.4 建一个自己的工具箱

我不建议你把所有工具都打开。那会影响性能。我通常只开 2~3 个。举个例子,在看 LazyColumn 滑动性能时,我会同时打开:

  • CPU Profiler(用于看帧率和调用栈)
  • Compose UI Checker 的 Floating Debug Panel(用于看重组次数)
  • 以及一个自定义的状态快照面板(用于确认数据源是否变化)

这三种信息交叉比对,基本能定位出 90% 以上的性能原因。

实用建议:创建一个快捷启动脚本或 AS Plugin,将常用工具的开启指令自动化。比如我写了一个简单的 Gradle Task,在 Debug 编译时自动注入所有工具开关配置。

总结一下:Compose 的工具链并没有多么神秘。把它们理解了、用对了,很多坑其实根本到不了你面前。这一章作为一个全景图,后面章节会逐一拆解每个工具的实战用法。到时候我会拿真实项目踩过的坑来说话,那样你听起来会更落地。