一句话说透Android里面的Surface绘制原理

432 阅读2分钟

一句话总结

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(比如视频浮窗)。

四、卡顿是怎么产生的?

  1. 主线程卡了onDraw() 里写了耗时操作,没在 16ms(60Hz)内画完。
  2. Buffer 不够用:App 画得太慢,Buffer 队列被掏空(生产者-消费者失衡)。
  3. VSync 没对齐:错过 VSync 信号,只能等下一个周期(肉眼可见的掉帧)。

五、终极绘制流程图

App 画图 → 丢进 Buffer → SurfaceFlinger 拼图 → 屏幕驱动 → 发光像素
       ↑               | 
       VSync 信号       | 
       ←←←←←←←←←←←←←←←←← 

一句话总结各角色

  • Surface:App 的画布
  • BufferQueue:装画布的传送带(双缓冲)
  • SurfaceFlinger:拼图师傅
  • VSync:流水线节拍器
  • GPU:苦力搬砖工(处理图形计算)