Android应用的调试
Android应用的调试:保留第四版正文机制,以所有者—状态—结果合同、事件轨迹和章专属故障完成可重放验收。
学习目标
- 能沿“Android应用的调试”的用户事件解释Android组件、状态所有者、线程与销毁边界。
- 能围绕“掌握 Android Studio 调试工具——Logcat 日志过滤、断点调试、变量监视和堆栈追踪分析。”改出一个可运行结果,并用前后状态而非组件数量验收。
- 能在旋转、进程重建、拒权、离线或无效输入中选择适用反例,定位首个状态分叉。
- 能用构建指纹、用户操作、状态快照、原始日志和行为断言独立重放结论,并标明第四版机制与现代targetSdk政策的边界。
Bug 来了——先看黑匣子
用户说「闪退」,你的第一步不是改代码,而是打开 ↡Android Studio 中显示系统和应用运行时日志的窗口,按时间与级别输出调试信息。。配合断点和堆栈追踪,大多数问题能在十分钟内定位到文件和行号。
Logcat 过滤
典型崩溃行:
E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.NullPointerException
at com.example.MainActivity.onCreate(MainActivity.kt:42)
读法:异常类型 → 你的包名 → 行号。
① 选择日志级别
在 Logcat 顶部下拉框将 Log Level 设为 Error(或 Warn+Error),过滤掉无关的 Debug 和 Verbose 输出。崩溃日志的优先级一定是 Error。
断点调试
| 类型 | 用途 |
|---|---|
| 普通断点 | 暂停查看变量 |
| 条件断点 | 如 index == 99,循环里只停一次 |
| 异常断点 | Run → View Breakpoints → Any exception,崩溃即停 |
堆栈追踪
从下往上读,第一个你的包名通常是根因:
at com.example.MainActivity.loadData(MainActivity.kt:42) ← 根因
at com.example.MainActivity.onCreate(MainActivity.kt:18)
at android.app.Activity.performCreate(...)
小结
- Crash → Logcat Error + 堆栈第一行自己的代码
- ANR → 主线程堆栈找阻塞点
- 断点:条件断点省时间,异常断点抓崩溃
练习
问题 1:“第5章 Debugging Android Apps”覆盖哪些正式节点和项目主线?
问题 2:怎样建立本页最小可执行实验?
问题 3:为什么只在正常点击路径运行不能证明完成?
问题 4:怎样设计能推翻当前实现的反例?
问题 5:从第4版语境迁移到现代目标SDK时如何控制变量?
问题 6:本页达到独立交接标准需要什么?
名词解释
本章出现的专业名词,用大白话再讲一遍。
- Logcat
Android Studio 中显示系统和应用运行时日志的窗口,按时间与级别输出调试信息。排查闪退、异常的第一站。
- ANR
Application Not Responding——主线程阻塞超约 5 秒,系统弹窗。常见原因:主线程 IO、死锁、过度布局。
- 堆栈追踪(Stack Trace)
异常时的方法调用链。从下往上读,定位第一个业务代码帧。
“Android应用的调试”不使用未获授权的纸书正文;InformIT出版信息与授权电子版完整目录只用于确认第四版32章、269个正式目录节点和时代语境,第四版官方勘误用于识别工具链变更。下列中文解释、图示、交互、代码与练习均为独立教学重写,平台行为再以Android Developers的一手文档复核。
为什么“Android应用的调试”必须回到可观察状态
“Android应用的调试”的学习结果不是记住类名,而是能预测“掌握 Android Studio 调试工具——Logcat 日志过滤、断点调试、变量监视和堆栈追踪分析。”在一次输入、一次重建和一次失败中的不同状态,并指出哪条Android合同产生差异。
第四版机制逐项深读
5. Debugging Android Apps
在“Android应用的调试”中,“5. Debugging Android Apps”从症状回溯首个异常帧、日志事件或状态分叉;修复证据必须包含可复现输入和失败前后的同一断言。
Exceptions and Stack Traces
在“Android应用的调试”中,分析“Exceptions and Stack Traces”区分编译、运行时、布局、线程与资源问题,避免在后续连锁报错处停止定位。
Android-Specific Debugging
在“Android应用的调试”中,“Android-Specific Debugging”从症状回溯首个异常帧、日志事件或状态分叉;修复证据必须包含可复现输入和失败前后的同一断言。
Challenge: Exploring the Layout Inspector
在“Android应用的调试”中,“Challenge: Exploring the Layout Inspector”的视觉正确性必须与语义树一致;看得见但读屏无名称、焦点不可达或点击区过小仍判失败。
Challenge: Exploring the Profiler
在“Android应用的调试”中,分析“Challenge: Exploring the Profiler”区分编译、运行时、布局、线程与资源问题,避免在后续连锁报错处停止定位。
“Android应用的调试”验收回顾
“Android应用的调试”只有在构建指纹、用户操作、状态快照、原始日志和行为断言能够从相同基线再次得到相同断言时才通过;第四版机制与现代平台政策分别记录,不用新API名称掩盖旧行为。
← 上一页:UI状态的保存与恢复 · 下一页:第二个Activity →
章专属可重放状态实验
先预测“重放最小失败用例并一次只改变一个原因”发生后,测试、Logcat、断点与问题工件的责任人应怎样改变失败输入、线程、异常、调用栈和修复假设;再操作三个实验。第四版示例与当前 Android 政策分别记录,实验不把新 API 名称倒填为原书内容。
实验一:所有者—状态—结果合同
选择任一正式目录节点和正常/边界场景,检查它是否真的进入本章状态合同。目录标题只有同时出现在解释、可视状态和交付证据中才算覆盖。
Owner · state · observable result
Android应用的调试:状态合同
从稳定失败、堆栈首个业务帧和设备状态定位 Android 缺陷
验证场景
第四版正式目录节点
debugging · 正常任务
5. Debugging Android Apps:固定 SDK、设备配置和初始状态,触发“重放最小失败用例并一次只改变一个原因”
冻结入口:5. Debugging Android Apps
记录测试、Logcat、断点与问题工件的责任人的初始失败输入、线程、异常、调用栈和修复假设
观察:失败测试、完整堆栈、断点快照、修复差异和回归结果中的“5. Debugging Android Apps”轨迹
预期:由测试、Logcat、断点与问题工件的责任人提交失败输入、线程、异常、调用栈和修复假设,并持续满足“同一失败输入在修复前稳定失败、修复后稳定通过且邻近用例不回归”
实验二:事件与生命周期轨迹
沿五次转换逐步执行“重放最小失败用例并一次只改变一个原因”。每一步只允许测试、Logcat、断点与问题工件的责任人按职责提交状态,并持续核对“同一失败输入在修复前稳定失败、修复后稳定通过且邻近用例不回归”。
Deterministic event replay
Android应用的调试:事件轨迹
不变量:同一失败输入在修复前稳定失败、修复后稳定通过且邻近用例不回归
交付证据:失败测试、完整堆栈、断点快照、修复差异和回归结果
实验三:章专属反例与同输入恢复
注入“捕获异常或删除日志让界面不崩,却没有修复无效状态”,保存第一个偏离点;撤销后以完全相同的 SDK、设备状态和用户事件重放。只有失败测试、完整堆栈、断点快照、修复差异和回归结果一起恢复才算修复。
Fault · cancel · restore
Android应用的调试:反例与恢复
故障:捕获异常或删除日志让界面不崩,却没有修复无效状态
第 1 次使用相同 SDK、设备配置、初始状态与用户事件
保持正常输入不变,仅注入“捕获异常或删除日志让界面不崩,却没有修复无效状态”
同一失败输入在修复前稳定失败、修复后稳定通过且邻近用例不回归
失败测试、完整堆栈、断点快照、修复差异和回归结果