一、先讲一个真实的故事
我见过两种Compose开发者。
第一种,写了半年Compose,遇到问题就搜“Compose XXX报错怎么办”。他知道LazyColumn怎么用,但不知道key为什么重要;会用remember,但说不清rememberSaveable和它的区别;能写出能跑的界面,但性能一卡就束手无策。
第二种,同样写了半年Compose。他遇到问题会先看编译器报告,用Layout Inspector定位重组热点,翻官方文档的Performance章节,然后精准地改那一行。他不仅知道怎么写,还知道为什么这么写。
两个人的差距,不在智商,不在经验,而在工具箱——他们手里有什么工具,以及知不知道什么时候用哪个。
这一课,我们就来把你从第一种人变成第二种人。
二、核心开发工具:Android Studio的Compose武器库
2.1 @Preview:用得最多,也最容易被低估
@Preview是Compose开发中使用频率最高的工具。但大多数人只用了它10%的能力。
基础用法:
@Preview(showBackground=true)@ComposablefunGreetingPreview(){MyAppTheme{Greeting("Android")}}进阶用法——多状态预览:
@Preview(name="加载中",showBackground=true)@ComposablefunProductListPreview_Loading(){MyAppTheme{ProductListScreen(uiState=ProductListUiState(isLoading=true),onProductClick={},onRetry={})}}@Preview(name="错误",showBackground=true)@ComposablefunProductListPreview_Error(){MyAppTheme{ProductListScreen(uiState=ProductListUiState(error="网络连接失败"),onProductClick={},onRetry={})}}@Preview(name="有数据",showBackground=true)@ComposablefunProductListPreview_Data(){MyAppTheme{ProductListScreen(uiState=ProductListUiState(products=listOf(Product(1,"商品A",99.0),Product(2,"商品B",199.0))),onProductClick={},onRetry={})}}多设备预览:
@Preview(name="手机竖屏",widthDp=360,heightDp=640)@Preview(name="手机横屏",widthDp=640,heightDp=360)@Preview(name="平板",widthDp=800,heightDp=1280)@Preview(name="折叠屏展开",widthDp=673,heightDp=841)@ComposablefunResponsivePreview(){MyAppTheme{AdaptiveLayout()}}多语言预览:
@Preview(name="English",locale="en")@Preview(name="中文",locale="zh")@Preview(name="العربية",locale="ar")@ComposablefunLocalizedPreview(){MyAppTheme{HomeScreen()}}深浅色预览:
@Preview(name="浅色",uiMode=Configuration.UI_MODE_NIGHT_NO)@Preview(name="深色",uiMode=Configuration.UI_MODE_NIGHT_YES)@ComposablefunThemePreview(){MyAppTheme{HomeScreen()}}交互式预览:Android Studio的预览面板支持直接在预览里点击按钮、输入文字、滚动列表。不用运行到设备上就能测试交互。
动画预览:预览面板支持逐帧检查动画效果,可以暂停、播放、慢放。
实时模板:
| 输入 | Tab后生成 |
|---|---|
comp | @Composable fun Xxx() { } |
prev | @Preview @Composable fun XxxPreview() { } |
paddp | Modifier.padding(X.dp) |
fillo | Modifier.fillMaxSize() |
lazycol | LazyColumn { items() { } } |
2.2 Live Edit:改代码,立刻看到
Live Edit让你修改代码后立即在运行中的设备上看到变化,不需要完整重新构建。对调整UI细节特别有用——改一个padding值,保存,立刻看到效果。
适用场景:调整颜色、间距、文字、简单布局。
不适用场景:修改函数签名、添加新依赖、修改Manifest。
2.3 Layout Inspector:性能调试的核心
Layout Inspector是Compose性能调试的第一工具。它能实时查看运行中应用的Compose布局树,显示每个可组合项的重组次数和跳过次数。
使用方式:运行App → Tools → Layout Inspector → 选择进程。
怎么看:如果某个组件的重组次数很高,但它的参数并没有变化——说明它无法被跳过。这就是优化目标。
进阶功能:
- Compose UI Check:检查无障碍和自适应布局问题。
- Recomposition Counts:实时查看每个组件的重组次数。
- Semantics面板:查看语义树结构,调试无障碍问题。
2.4 Composition Tracing
Composition Tracing把你的可组合函数追踪到系统Trace中,让你看到每次重组在哪个函数中发生、耗时多少。结合Android Studio的Profiler,可以精确定位性能瓶颈。
使用方式:Profiler → CPU时间轴 → System Trace → Record → 操作应用 → Stop。
三、调试工具箱:从“出问题”到“找到根因”
3.1 编译器报告:从源头看稳定性
第16课讲过编译器报告。这里再强调一次,因为它是最被低估的调试工具。
开启方式:
android{composeCompiler{reportsDestination=layout.buildDirectory.dir("compose_compiler")metricsDestination=layout.buildDirectory.dir("compose_compiler")}}编译后,在build/compose_compiler/目录下会生成报告文件。打开composables.txt:
restartable skippable fun ArticleCard( stable article: Article )restartable:可以独立重组skippable:参数没变时可以跳过stable:参数是稳定的
如果看到:
restartable fun ArticleCard( unstable article: Article )没有skippable,参数是unstable——这就是问题所在。
3.2 语义树打印
测试中可以用printToLog打印语义树:
composeTestRule.onRoot().printToLog("SemanticsTree")输出的日志会显示整个语义树的结构,帮你理解节点的层次和属性。调试无障碍问题时特别有用。
3.3 日志与断点
在可组合函数里打日志要小心,因为重组会频繁执行。用SideEffect或LaunchedEffect来打日志:
@ComposablefunMyComponent(){SideEffect{Log.d("MyComponent","重组了")}}断点可以打,但注意可组合函数可能被多次调用,断点会频繁触发。
3.4 常见问题的快速排查表
| 症状 | 可能原因 | 排查工具 |
|---|---|---|
| 滑动卡顿 | 重组过多 | Layout Inspector看重重组次数 |
| 界面不更新 | 状态没触发重组 | 检查是否用了mutableStateOf |
| 状态丢失 | 忘了remember | 检查是否用了remember |
| 深色模式失效 | 硬编码颜色 | 检查是否用了MaterialTheme.colorScheme |
| 列表状态错乱 | 没传key | 检查items是否传了key |
| 编译报错“不稳定” | 参数不稳定 | 看编译器报告 |
| 内存泄漏 | 协程没取消 | 检查是否用了GlobalScope |
四、测试工具箱:从单元测试到截图测试
4.1 测试依赖
dependencies{androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.6")debugImplementation("androidx.compose.ui:ui-test-manifest:1.7.6")testImplementation("junit:junit:4.13.2")androidTestImplementation("androidx.test.ext:junit:1.2.1")}4.2 测试查找器速查
// 按文字查找onNodeWithText("登录")onNodeWithText("登录",substring=true)// 按测试标签查找(推荐)onNodeWithTag("loginButton")// 按内容描述查找onNodeWithContentDescription("删除")// 查找所有匹配节点onAllNodesWithTag("item")4.3 常用断言速查
.assertExists().assertDoesNotExist().assertIsDisplayed().assertTextEquals("Hello").assertTextContains("ell").assertIsOn()/.assertIsOff().assertIsEnabled()/.assertIsNotEnabled().assertIsSelected()/.assertIsNotSelected()4.4 常用操作速查
.performClick().performLongClick().performTextInput("Hello").performTextClearance().performScrollTo().performTouchInput{swipeUp()}4.5 截图测试
Compose Preview Screenshot Testing是Android Studio提供的截图测试工具。你可以为同一组件定义多个@Preview,测试框架会自动渲染并对比截图。
工作流程:
- 写
@Preview函数 - 运行截图测试任务
- 首次运行时生成基准截图
- 后续运行时对比截图,发现差异就报错
4.6 测试金字塔
| 层级 | 测试对象 | 工具 | 运行速度 |
|---|---|---|---|
| 单元测试 | ViewModel、UseCase、Repository | JUnit + kotlin.test | 毫秒级 |
| 组件测试 | 单个可组合函数 | ComposeTestRule | 秒级 |
| 集成测试 | 多个页面、导航 | ComposeTestRule + Hilt | 秒级 |
| 端到端测试 | 整个应用流程 | UI Automator | 分钟级 |
建议:大部分测试应该是单元测试和组件测试,少量集成测试,极少端到端测试。
五、第三方库生态:值得关注的宝藏库
5.1 图片加载:Coil
AsyncImage(model="https://example.com/image.jpg",contentDescription=null,modifier=Modifier.size(200.dp))注意:Accompanist-Coil已废弃,推荐直接使用io.coil-kt:coil-compose。
5.2 导航:Voyager / Decompose
Compose Multiplatform上流行的导航库,比Navigation Compose更灵活,特别适合跨平台场景。
5.3 网络:Ktor
valclient=HttpClient{install(ContentNegotiation){json()}}suspendfungetArticles():List<Article>=client.get("https://api.example.com/articles").body()5.4 数据库:SQLDelight
从SQL语句生成类型安全的Kotlin代码,跨平台数据库方案。
5.5 依赖注入:Koin
valappModule=module{single<ArticleRepository>{ArticleRepositoryImpl(get(),get())}viewModel{ArticleListViewModel(get())}}5.6 其他值得关注的库
| 库 | 用途 |
|---|---|
| Haze | 背景模糊效果 |
| Compose DND | 拖拽功能 |
| Compose Rich Editor | 富文本编辑器 |
| colorpicker-compose | 颜色选择器 |
| Landscapist | KMP图片加载 |
| kotlinx-datetime | 跨平台日期时间 |
| kotlinx-serialization | 跨平台序列化 |
六、学习资源:官方与社区
6.1 官方文档核心章节
| 章节 | 内容 |
|---|---|
| Get started | 入门教程 |
| Thinking in Compose | 声明式思维 |
| Managing state | 状态管理 |
| Lifecycle of composables | 生命周期 |
| Modifiers | 修饰符系统 |
| Side-effects | 副作用管理 |
| Jetpack Compose Phases | 渲染管线三阶段 |
| Performance | 性能优化 |
| Semantics | 语义树 |
| CompositionLocal | 局部作用域数据 |
| Accessibility | 可访问性 |
| Adaptive layouts | 自适应布局 |
6.2 动手资源
- Compose Codelab:官方提供的动手教程,涵盖基础、状态、列表、动画、测试。
- Now in Android:Google官方的开源示例应用,展示了Compose的最佳实践。
- Jetnews:官方示例,展示了Compose在实际应用中的用法。
- Android Skills:CLI工具,快速设置测试基础设施。
android skillsaddtesting-setup6.3 视频课程
Philipp Lackner的YouTube频道是学习Compose和KMP的优质资源,有完整的免费课程。
6.4 社区资源
- GitHub awesome列表:
kmp-awesome、awesome-android-ui - klibs.io:搜索KMP库
- Compose Multiplatform官方教程:从零创建CMP应用
七、成长路线图:从初学者到高级开发者
第一阶段:基础入门(1-2周)
目标:能写出简单的Compose页面。
学习内容:
@Composable函数、Column/Row/BoxModifier链式调用Text、Button、Image等基础组件@Preview预览
练习:做一个静态的个人名片页面。
检验标准:能独立写出一个包含头像、名字、简介、按钮的卡片。
第二阶段:状态与交互(2-3周)
目标:能实现有交互的页面。
学习内容:
mutableStateOf、remember、rememberSaveable- 状态提升、单向数据流
LaunchedEffect、SideEffectTextField输入处理
练习:做一个计数器、一个登录表单。
检验标准:能独立写出一个带输入验证、加载状态、错误提示的表单页面。
第三阶段:列表与导航(2-3周)
目标:能实现多页面应用。
学习内容:
LazyColumn、LazyRow、LazyVerticalGridkey、contentType- Navigation Compose、类型安全路由
- 底部导航栏
练习:做一个待办事项应用,带列表和详情页。
检验标准:能独立写出一个带底部导航、列表、详情页、参数传递的应用。
第四阶段:主题与动画(2-3周)
目标:能做出好看的界面。
学习内容:
MaterialTheme、ColorScheme、Typography、Shapes- 深色模式、动态取色
animate*AsState、AnimatedVisibility、animateContentSize- 手势:
clickable、draggable、transformable
练习:给待办事项应用加上主题系统和动画效果。
检验标准:能独立实现一套完整的主题系统,支持深浅色切换,给列表加上进入退出动画。
第五阶段:架构与协程(3-4周)
目标:能写出结构清晰、可维护的应用。
学习内容:
- ViewModel + StateFlow
- Repository模式、UseCase
- Hilt依赖注入
- 协程、Flow、
snapshotFlow collectAsStateWithLifecycle
练习:把待办事项应用重构为分层架构,加上网络请求。
检验标准:能独立设计一个分层架构,UI/ViewModel/UseCase/Repository各层职责清晰,依赖注入配置正确。
第六阶段:测试与性能(2-3周)
目标:能写出有质量保障的高性能应用。
学习内容:
- Compose测试API、语义树
- Repository/ViewModel/UI各层测试
- Layout Inspector、编译器报告
- 稳定性、
derivedStateOf、remember优化 - LazyColumn性能优化
练习:给待办事项应用补全测试,并用Layout Inspector分析性能。
检验标准:能为一个完整应用写出各层测试,能用工具定位并解决性能问题。
第七阶段:进阶与跨平台(持续)
目标:成为Compose专家。
学习内容:
- 自定义绘制、
Canvas、DrawScope - Compose Multiplatform
- 安全、权限、隐私
- 自适应布局
- 可访问性
- 国际化
- AI集成
练习:把待办事项应用迁移到Compose Multiplatform。
检验标准:能独立完成一个多平台应用,代码在Android、iOS、桌面都能运行。
八、常见陷阱速查
| 陷阱 | 后果 | 解决方案 |
|---|---|---|
忘记remember | 重组时状态丢失 | remember { mutableStateOf(...) } |
| 在组合中修改状态 | 无限重组 | 状态修改放在事件回调 |
| 列表不传key | 状态错乱、性能差 | key = { it.id } |
| 硬编码颜色 | 深色模式失效 | 用MaterialTheme.colorScheme |
| 在组合中做耗时操作 | 掉帧 | 移到LaunchedEffect/ViewModel |
用GlobalScope | 协程泄漏 | 用viewModelScope/rememberCoroutineScope |
| 组合阶段读高频状态 | 每帧重组 | derivedStateOf |
List参数不稳定 | 无法跳过重组 | ImmutableList或@Immutable |
| Debug模式测性能 | 误判 | 用Release模式 |
忘记testTag | 测试不稳定 | 给交互元素加testTag |
| 用left/right | RTL不生效 | 用start/end |
| 字符串硬编码 | 无法国际化 | 用stringResource |
| 图标缺contentDescription | 无障碍失效 | 加上描述或传null |
| 触摸目标小于48dp | 难以点击 | 用IconButton保证最小尺寸 |
九、工具箱的思维模型
最后,用一张“思维模型”来总结这一课:
第一层:写代码的工具。@Preview多状态预览,Live Edit即时反馈,实时模板提升效率。
第二层:调试的工具。Layout Inspector看重组,编译器报告看稳定性,语义树打印看结构。
第三层:测试的工具。单元测试测逻辑,组件测试测UI,截图测试测视觉。
第四层:生态的工具。Coil加载图片,Ktor请求网络,SQLDelight操作数据库,Koin注入依赖。
第五层:成长的工具。官方文档打基础,Codelab练手感,Now in Android学最佳实践,开源项目拓视野。
贯穿始终的原则:知道什么时候用什么工具。遇到卡顿,先看Layout Inspector,再看编译器报告;遇到Bug,先写测试复现,再调试修复;遇到新需求,先查官方文档,再看社区方案。
十、小结与下一课预告
这一课我们系统性地盘点了Compose开发者的完整工具箱。关键点回顾:
- 开发工具:
@Preview(多状态、多设备、多语言、深浅色)、Live Edit、Layout Inspector、Composition Tracing。 - 调试工具:编译器报告看稳定性,语义树打印看结构,常见问题快速排查表。
- 测试工具:单元测试、组件测试、截图测试,测试金字塔。
- 第三方库:Coil(图片)、Ktor(网络)、SQLDelight(数据库)、Koin(DI)、Voyager/Decompose(导航)。
- 学习资源:官方文档核心章节、Codelab、Now in Android、Jetnews、社区资源。
- 成长路线图:七个阶段,从基础入门到进阶跨平台,每个阶段有明确的学习内容、练习和检验标准。
- 常见陷阱:14个高频陷阱速查表。
- 工具箱思维模型:写代码、调试、测试、生态、成长——五层工具,知道什么时候用什么。
工具箱的意义不在于工具本身,而在于你知道什么时候用哪个。一个经验丰富的开发者,不是记住了所有API,而是遇到问题时知道去哪里找答案,用什么工具定位,按什么顺序排查。
下一课,也是这个系列真正的收官之课,我们会做一次Compose的完整回顾与未来展望。内容包括:Compose从诞生到现在的演进历程、每个版本的关键变化、2026年路线图上的功能、以及Compose在Android、多平台、AI时代的未来方向。这是对整个系列的总结和升华。
课后练习建议:对照这一课的成长路线图,评估自己目前处于哪个阶段。然后找一两个你还不熟悉的工具或库,专门花时间把它用起来。每掌握一个新工具,你的开发效率就会提升一个台阶。