ANR分析流程

4 阅读2分钟

Android ANR 分析

一、先把 ANR 想成一件事

把 App 想成一条单车道公路

  • 主线程 = 唯一车道
  • 所有 UI 操作 = 必须走这条路
  • ANR = 这条路被堵住太久

二、ANR 分析只做一件事

找到:谁把这条路堵住了


三、实战第一步:先看 traces(90% 问题在这里解决)

你打开 ANR 文件,第一件事:

👉 找 main 线程

"main"

👉 看最后一行在干嘛

at xxx.xxx()

这一行非常重要:

它就是“卡住的现场”


四、只用四种方式理解所有 ANR(核心)

看到 main 线程栈,不要复杂化,只归类成四种:


① 在干活(自己慢)

画面:主线程在搬砖

表现:

  • IO(文件 / 数据库)
  • 网络请求
  • JSON / Bitmap 处理

👉 栈特点:RUNNABLE,一直在执行

结论:

事情没错,但不该在主线程做


② 在等门(等锁)

画面:主线程在门口等钥匙

表现:

waiting to lock

👉 核心不是主线程,而是:

谁拿着锁不放


③ 在打电话(等结果)

画面:主线程在等别人回复

表现:

  • WAITING
  • Binder
  • join / wait

结论:

把“未知时间的事情”当成同步做了


④ 前面堵车(队列问题)

画面:前面车太慢,后面全堵住

表现:

  • 当前栈看起来不重
  • 但 UI 还是卡

结论:

前一个任务拖慢了整个消息队列


五、线程状态怎么用

线程状态只做一件事:

帮你快速判断方向

状态含义方向
RUNNABLE正在执行看是否耗时
BLOCKED等锁查锁
WAITING等结果查依赖

⚠️ 注意:

状态不告诉你原因,只告诉你类型


六、什么时候看 log(非常关键)

很多人误区是:一上来就看 log。

正确顺序是:


✔ 先看 traces(定位“卡在哪里”)


✔ log 只在三种情况看:

1️⃣ 栈看不出明显耗时

比如 main 在 MessageQueue


2️⃣ 要还原“发生顺序”

例如:
点击 → 跳转 → 加载 → 卡死


3️⃣ 怀疑“前面已经埋雷”

比如:
前一个页面已经慢了,但在这里爆发


👉 一句话:

traces 看“卡点”,log 看“过程”


七、一眼判断法(真正实用)

看到 main 栈,只问一句:

这件事,如果放在后台做,会不会更合理?

  • ✔ 会 → 主线程写错了
  • ❌ 不会 → 设计本身有问题

八、一个完整分析例子(帮助你建立直觉)

traces:

main:
at DataManager.getData()
waiting to lock

你看到什么:

  • 主线程在 getData
  • 在等锁

下一步思考:

  • 谁持有锁?
  • 持锁线程在干嘛?

结论:

主线程等待锁,但锁被子线程持有且执行耗时操作,导致 ANR


九、最终收敛(核心一句话)

ANR = 主线程被“做事”或“等待”卡住了


十、最重要的一句总结

先看栈找卡点,再用逻辑判断“这件事是否应该发生在主线程”