先记录发生了什么,再寻找日志
日志不是问题本身。为了让日志有解释力,先记下应用版本、设备系统版本、操作入口和大概时间。例如“打开设置页面后点击保存,界面立即退出”,比“App 闪退了”更容易定位。
下面的命令把当前日志缓冲区导出到电脑文件。它不会持续等待新日志,也不会主动清空缓冲区。文件可能包含其他应用或系统信息,请在分享前脱敏。
adb logcat -d -v threadtime > crash-log.txtthreadtime 格式可以帮助关联时间、PID 和 TID。设备的实际可用参数以 adb logcat --help 为准。系统版本、权限和厂商差异可能影响能读取的内容。
用时间窗口和进程缩小范围
先找到复现动作前后几秒,而不是在整份日志里只搜索一个包名。系统报告进程退出时,包名可能出现;异常栈中的库名则未必包含应用包名。仅按包名过滤可能丢掉关键上下文。
对 Java/Kotlin 崩溃,通常可以搜索 FATAL EXCEPTION、AndroidRuntime 和 Caused by。对 native 崩溃,则应关注 signal、Abort message、backtrace 等线索。ANR 是另一类问题,不能因为界面不响应就按异常堆栈处理。
本站的日志片段筛选器可以按关键词保留命中行及上下文,计算在当前浏览器执行。但它只是文本筛选工具,不会判断哪个异常一定是根因。
沿异常链阅读,而不是只抄最后一行
下面是一段教学示例,不是本站的真实设备测试记录:
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity
Caused by: java.lang.IllegalStateException: Missing configuration
at example.app.Config.require(Config.kt:24)
at example.app.MainActivity.onCreate(MainActivity.kt:18)最外层异常说明启动 Activity 失败;内层异常指出缺少配置;第一条属于应用代码的栈帧给出了优先检查的位置。此时直接修改 MainActivity 的生命周期顺序未必有效,应先确认配置的来源、加载时机和失败路径。
更深的 Caused by 往往提供原因,但也不是机械地“最深一层必然是根因”。要结合代码调用链,以及异常出现前的状态判断。
Release 堆栈需要匹配构建产物
压缩后的类名和行号可能无法直接对应源代码。对启用 R8 的版本,保存与发布包严格对应的 mapping 文件;对 native 崩溃,保存同一构建的符号。仅仅版本名称相同,也不代表构建内容相同。
把版本号、versionCode、构建标识和产物摘要放到问题记录中。不要使用另一个分支的 mapping 去解释现有堆栈,否则看似清晰的文件名也可能指向错误位置。
修复后的验收清单
重新执行原来的操作路径,确认异常没有再次出现,并检查页面是否真正完成预期功能。如果只是吞掉异常,界面不再退出但数据没有保存,问题仍然存在。
- 保留修复前的最小日志片段与复现步骤。
- 记录修复版本和测试设备,区分 Debug 与 Release。
- 对失败输入、缺失配置或断网等触发条件再执行一次。
- 分享日志前去除账号、令牌、设备标识和业务内容。