这篇文章主要讲安卓手机卡顿的原理,以及如何用 Systrace 工具分析流畅度问题,用大白话总结如下:
一、什么是卡顿?用户和开发者的理解不同
-
用户眼中的卡顿:滑动列表时画面卡住、应用启动慢、点击没反应、动画不连贯等。
-
开发者的分类:
-
流畅度问题:滑动掉帧、动画卡顿(比如刷抖音时画面一顿一顿)。
-
响应速度问题:点击按钮后很久才反应(比如打开微信慢)。
-
稳定性问题:操作后闪退或卡死(比如玩游戏时突然黑屏)。
-
核心原因:这三类问题本质都是主线程处理任务超时,就像工厂流水线堵车,导致画面更新慢。
二、一帧画面是怎么 “画” 出来的?卡顿如何发生?
手机要显示一帧画面,流程像工厂流水线:
-
闹钟响(Vsync 信号) :屏幕刷新前会发一个 “开始画画” 的信号(约 16.6ms 一次,对应 60fps)。
-
主线程干活:处理用户输入(比如滑动)、动画计算、界面布局(量尺寸、摆位置)。
-
渲染线程画图:用 GPU 把界面画到 “画布”(Buffer)上。
-
拼图画(SurfaceFlinger) :把所有 App 的 “画布” 合成一张图,交给屏幕显示。
卡顿怎么来的?
如果任何一步超时(比如主线程算布局太慢),就会导致:
- 下一帧没画完,屏幕只能重复显示上一帧(画面卡住)。
- 就像做饭时切菜太慢,导致上菜延迟,客人等得不耐烦。
三、关键机制:为什么会超时?系统怎么 “补救”?
-
主线程的 “快递系统”(Message 机制)
主线程靠 Handler/Looper/MessageQueue 传递任务,像快递员按顺序送包裹。如果某个任务(比如加载大图)耗时太长,后面的任务都得排队,导致整体卡顿。 -
屏幕刷新的 “闹钟”(Vsync)
屏幕每秒刷新 60 次(60Hz),对应每 16.6ms 需要一帧画面。如果 App 在 16.6ms 内没画完,就会掉帧(fps 降低),比如从 60fps 降到 40fps,用户就会感觉卡。 -
画布不够用?三 Buffer 救场!
- 双 Buffer:只有 2 个 “画布”,如果 App 画画慢,SurfaceFlinger 拿不到新画布,就会重复显示旧画面(卡顿)。
- 三 Buffer:有 3 个画布轮转,即使某一步慢了,也能暂时用多余的画布救急,减少卡顿次数(但会多占内存)。
-
用户操作的 “传递链”(Input 流程)
手指滑动时,InputReader 读取触摸事件,InputDispatcher 分发到 App,主线程被唤醒处理。如果这个链条任何一环卡住(比如系统忙不过来),就会导致滑动不跟手。
四、如何用 Systrace 抓出卡顿元凶?
Systrace 是个 “监控摄像头”,能记录整个画面渲染流程:
-
看主线程是否被耗时任务阻塞(比如 GC 垃圾回收、复杂布局)。
-
看渲染线程是否卡在读 Buffer 或 GPU 渲染慢。
-
看 SurfaceFlinger 合成是否超时,或 BufferQueue 里的画布是否不够用。
举个例子:如果 Systrace 显示某一帧的主线程处理用了 25ms(超过 16.6ms),就说明这一帧可能导致卡顿,需要优化主线程任务(比如把耗时操作移到后台线程)。
五、总结:卡顿就是 “流水线堵车”,Systrace 是 “交通警察”
-
卡顿本质:App 渲染一帧的时间超过了屏幕刷新周期,导致画面更新不及时。
-
分析思路:用 Systrace 查看流水线哪一步堵了(主线程 / 渲染线程 / GPU/SurfaceFlinger),然后针对性优化(比如减少主线程计算、增加 Buffer 数量、优化 GPU 渲染)。
这篇文章是系列第一篇,后续会教具体的实战分析案例,帮助开发者通过 Systrace 解决实际卡顿问题。