一句话总结:
Surface 就像一块画布,App 在这块画布上画画(绘制像素),系统(SurfaceFlinger)负责把多块画布拼成一幅大画,最后贴在手机屏幕上。
一、Surface 是什么?
-
比喻:Surface 就是一块“透明玻璃板”,App 把要显示的内容画在这块玻璃上。
-
实际作用:
- 每个窗口(Activity、Dialog、游戏画面)都有自己的 Surface。
- Surface 背后对应一块内存(Buffer),专门存像素数据(比如按钮、文字、图片)。
二、绘制流程(工厂流水线)
比喻:把手机屏幕想象成一个不断翻页的连环画,Surface 的绘制就是工厂流水线生产每一帧画面:
步骤 1:App 开始画画(生产一帧)
- 普通 View:通过
onDraw()
用 Canvas 画(比如按钮、文字)。 - 游戏/视频:用 OpenGL 或 Vulkan 直接画在 Surface 上。
// 例子:SurfaceView 绘制一个圆
val surfaceHolder = surfaceView.holder
surfaceHolder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
// 拿到 Surface 的 Canvas(画笔)
val canvas = holder.lockCanvas()
canvas.drawColor(Color.WHITE)
val paint = Paint().apply { color = Color.RED }
canvas.drawCircle(100f, 100f, 50f, paint)
holder.unlockCanvasAndPost(canvas) // 交卷!
}
})
步骤 2:双缓冲机制(防止闪烁)
- 前缓冲(Front Buffer) :当前屏幕上显示的画面。
- 后缓冲(Back Buffer) :App 正在偷偷画的新画面。
- 翻页:画完后,系统把后缓冲和前缓冲瞬间交换(swap),用户看不到中间过程。
比喻:像黑板报,先在草稿纸上画好(后缓冲),整版擦掉后瞬间贴上(防止半成品画面闪烁)。
步骤 3:SurfaceFlinger 拼图
- SurfaceFlinger:Android 系统的一个“拼图大师”。
- 工作:把所有 App 的 Surface(比如微信、游戏)按层级叠在一起(Z-order),合并成最终画面。
- 输出:合并后的数据交给屏幕驱动,最终显示。
步骤 4:VSync 信号(节拍器)
- VSync(垂直同步) :屏幕刷新率的节奏(比如 60Hz 就是每秒 60 次)。
- 作用:App 必须在 VSync 信号到来时完成绘制,否则会丢帧(卡顿)。
三、为什么 SurfaceView 适合游戏和视频?
-
普通 View:所有 View 共用一个 Surface(主线程绘制),容易卡顿。
-
SurfaceView:
- 有自己独立的 Surface,单独线程绘制(不卡主线程)。
- 直接操作像素(Canvas/OpenGL),适合高频刷新。
- “挖洞”效果:SurfaceView 的层级在窗口之下,可以覆盖其他 View(比如视频浮窗)。
四、卡顿是怎么产生的?
- 主线程卡了:
onDraw()
里写了耗时操作,没在 16ms(60Hz)内画完。 - Buffer 不够用:App 画得太慢,Buffer 队列被掏空(生产者-消费者失衡)。
- VSync 没对齐:错过 VSync 信号,只能等下一个周期(肉眼可见的掉帧)。
五、终极绘制流程图
App 画图 → 丢进 Buffer → SurfaceFlinger 拼图 → 屏幕驱动 → 发光像素
↑ |
VSync 信号 |
←←←←←←←←←←←←←←←←←
一句话总结各角色
- Surface:App 的画布
- BufferQueue:装画布的传送带(双缓冲)
- SurfaceFlinger:拼图师傅
- VSync:流水线节拍器
- GPU:苦力搬砖工(处理图形计算)