SurfaceView介绍
普通 View 的绘制和用户响应都在 UI 主线程。耗时操作要丢到别的线程,否则会卡住界面;但后台线程又不能改 UI,例如在自定义 View 的
onDraw里从工作线程刷新是不允许的。
需要在别的线程画界面、要迅速刷新、或渲染很耗时,就用 SurfaceView。它内嵌一个 Surface,可以在后台线程绘制。
一、官方 API 怎么说
SurfaceView 继承 View,内嵌专门用于绘制的 Surface。你可以控制这个 Surface 的格式和尺寸;SurfaceView 负责它画在窗口的哪个位置。
Surface 是 Z-ordered 的,总在自己所在窗口的后面。SurfaceView 提供可见区域:区域内的 Surface 才看得见。排版受视图层级影响,兄弟结点会盖在上面——可用来放文字、按钮等遮盖物。若 Surface 上有透明控件,每次变化都要重算透明效果,影响性能。
通过 SurfaceHolder 访问 Surface,getHolder() 拿到接口。SurfaceView 变得可见时 Surface 被创建,隐藏前被销毁,以节省资源。要观察时机,重写 surfaceCreated / surfaceDestroyed。
核心是两条线程:UI 线程和渲染线程。注意:
-
所有 SurfaceView 和 SurfaceHolder.Callback 方法都应在 UI 线程(一般是主线程)调用。渲染线程访问的变量要同步。 -
Surface 可能被销毁,只在 surfaceCreated 和 surfaceDestroyed 之间有效,渲染线程必须访问合法 Surface。
二、自己的理解
1. 定义
可以直接从内存或 DMA 等硬件接口取得图像数据,是重要的绘图容器。
特点是:可以在主线程之外向屏幕绘图,避免画图太重阻塞主线程,提高反应速度。游戏里背景、人物、动画尽量在 Canvas 上画出。
2. 实现
继承 SurfaceView 并实现 SurfaceHolder.Callback。原则:所有绘图必须在 Surface 创建之后开始(Surface 可理解为显存映射,写入内容可直接复制到显存,所以快),销毁之前必须结束。因此 Callback 的 surfaceCreated / surfaceDestroyed 就是绘图代码的边界。
需要重写:
-
surfaceChanged(SurfaceHolder holder,int format,int width,int height):大小改变时激发。 -
surfaceCreated(SurfaceHolder holder):创建时激发,一般在这里启动画图线程。 -
surfaceDestroyed(SurfaceHolder holder):销毁时激发,一般停掉、释放画图线程。
整个过程:
-
继承 SurfaceView 并实现 Callback -
getHolder()得到 SurfaceHolder -
addCallback(callback)添加回调 -
lockCanvas()得到 Canvas 并锁定 -
在 Canvas 上画 -
unlockCanvasAndPost(canvas)结束锁定并提交显示
3. SurfaceHolder
可以当成 Surface 的控制器:操纵 Canvas 上的效果和动画,控制表面、大小、像素。几个方法:
-
addCallback(SurfaceHolder.Callback callback):给当前持有者一个回调对象。 -
lockCanvas():锁定画布,之后用返回的 Canvas 作画。 -
lockCanvas(Rect dirty):只锁一块脏区。提交后只改这块,内存吃紧的游戏可避免重画 dirty 外像素。 -
unlockCanvasAndPost(Canvas canvas):结束锁定并提交改变。
| 步骤 | 调用 | 含义 |
|---|---|---|
| 拿控制器 | getHolder() |
SurfaceHolder |
| 监听生命周期 | addCallback |
创建/销毁/尺寸变化 |
| 开画 | lockCanvas |
独占 Canvas |
| 提交 | unlockCanvasAndPost |
显示到屏幕 |
4. Surface 调用过程图
三、例子:矩形 + 计时器
一句话总结:SurfaceView 把 Surface 交给后台线程 lockCanvas / unlockCanvasAndPost;只在 Created 与 Destroyed 之间画,Callback 方法留在主线程。
转载请注明来源:SurfaceView介绍








