SurfaceView详解

基础理解

SurfaceView内嵌的Surface是在包含有SurfaceViewActivity窗口的后面, 用描述SurfaceViewLayer[图层]的Z轴位置 小于 用来描述Activity窗口的Layer的Z轴位置,因此SurfaceView是不可见的, SurfaceView提供了一个可见区域,只有在此可见区域内Surface部分内容才可见,SurfaceView在界面上的表现就像在Activity窗口挖了一个“黑洞”,以便显示它的UI。实际上就相当于在Activity窗口设置了一块透明区域

SurfaceViiew 与 View的区别

  • [1] SurfaceView拥有独立的绘图表面,因此 SurfaceViewUI可以在一个独立的线程中进行绘制,不占用主线程资源,可以实现复杂而高效的UI绘制,在窗口刷新是不需要重绘应用程序窗口
  • [2] View通过刷新来重绘视图,Android系统通过发出VSYNC信号来进行屏幕重绘,刷新间隔16ms,超过16ms则会导致丢帧或卡顿,此时的UI线程会被绘制函数阻塞导致无法相应造成ANR
  • [3] SurfaceView虽继承与View却拥有独立surface,不同应用窗口共享一个surface,不占用主线程的资源单独在一个线程进行绘制,因此比较高效。一般视频播放、直播、游戏都可以用 SurfaceView实现

使用详解

SurfaceView子类

  • GLSurfaceView
  • VideoView

SurfaceView中的MVC

若要使用SurfaceView我们还需了解它的两个组件来共同控制SurfaceView的展示,组成了一个完整的MVC模式

  • Surface.java 用于存放数据模型
  • SurfaceHolder.java 作为控制器的存在
  • SurfaceView.java 用来显示视图

SurfaceHolder

SurfaceView有三个回调方法可以监听SurfaceViewsurface生命周期,SurfaceView被创建出来后他拥有的surface不一定会被创建出来

  • SurfaceView变得可见 >>> surface被创建 >>> 可以开始绘制
  • SurfaceView隐藏前 >>> surface被销毁 >>> 释放其他资源

SurfaceView一般继承SurfaceHolderCallback接口,具体监控方法如下:

  • surfaceCreated(SurfaceHolder holder) 函数:第一次创建立即调用,做绘制界面的相关初始化操作,一般都是在新线程中绘制界面,不要放在此函数中绘制surface
  • surfaceChanged(SurfaceHolder holder, int format, int width,int height) 函数:当surface状态发生变化时调用,状态发生变化的范围包括 大小和格式
  • surfaceDestroyed(SurfaceHolder holder) 函数: 当surface被摧毁前调用,调用后不能继续使用surface,一般用来清理使用资源

双缓存

SurfaceView在更新视图时用了两个Canvas,一张frontCanvas画布 和一张backCanvas画布,每次实际上用于显示的是frontCanvas画布,而backCanvas画布用于存储上次更改前的视图;

当使用lockCanvas函数 获取画布时,我们得到的实际是backCanvas而不是正在显示的frontCanvas,当获取到的backCanvas上绘制完使用unlockCanvasAndPost(Canvas canvas) 提交backCanvas视图后,那么这张backCanvas将替代当前正在显示的frontCanvas,进而被展示出来;原来的frontCanvas会被切换到后台作为backCanvas存在。这样可以保证在绘制期间不会出现黑屏

SurfaceView类的成员变量mRequestedType用来决定绘制表面Surface的类型和内存的选择

  • SURFACE_TYPE_NORMAL
  • SURFACE_TYPE_BUFFERS
[1] SURFACE_TYPE_NORMAL

[1] 表示SurfaceView绘图表面所使用的内存是一块 普通内存
[2] 此内存由SufaceFlinger服务分配,应用程序内存自由访问它,可在它上面填充任意的UI数据,然后交由SurfaceFlinger服务来合成,显示在屏幕上
[3] SurfaceFlinger服务一段使用一个Layer对象来描述该SurfaceView的绘图表面

[2] SURFACE_TYPE_BUFFERS

[1] 表示SurfaceView绘图表面所使用的内存不是由SurfaceFlinger服务分配的,应用程序内部不能对它进行操作,所以不能调用lockCanvas来获取Canvas对象进行绘制
[2] 使用场景一般用于使用摄像头服务或视频播放服务,摄像头服务或视频服务会为该SurfaceView绘图表面创建一块内存,并将采集的预览图像数据或视频帧数据源源不断的填充到内存中,在SurfaceFlinger服务端使用LayerBuffer对象来描述该SurfaceView的绘图表面.

SurfaceView类的成员变量mRequestedType目前接收如下的参数:

SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface
SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface
SURFACE_TYPE_GPU:适用于GPU加速的Surface
SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供。

特别注意:

  • [1] 所有回调都是在 主线程 中执行的,绘制前必须获取合法的Surface才开始绘制,保证surfaceCreated函数surfaceDestoryed函数之间的状态为合法的
  • [2] SurfaceView不直接与Surface打交道,交由SurfaceHolderCanvas lockCanvas函数lockCanvas(Rect dirty)函数来锁定并获取Surface中的Canvas画布对象
  • [3] 通过在Canvas上绘制内容来修改Surface中的数据,若Surface被别的线程占用不可编辑 或 未创建 或 已被销毁,调用此函数返回 null
    unlockCanvas函数lockCanvas函数之间的Surface的内容是不进行缓存的,所以需要完全重绘Surface的内容
  • [4] 若想提高效率只绘制变化部分的内容则可以调用lockCanvas(Rect dirty)函数来实现绘制指定的dirty区域,这样区域外的内容会缓存起来,只对重绘区域作更新
  • [5] 在调用lockCanvas函数获取SurfaceCanvas后,SurfaceView会利用Surface的同步锁锁住画布Canvas,直到调用unlockCanvasAndPost(Canvas canvas)函数后才解锁画布并提交改变,将图形显示;这里的同步机制保证SurfaceCanvas在绘制过程中不会被改变(被销毁、修改),避免多个不同的线程同时操作一个Canvas对象

This ALL! Thanks EveryBody!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容