surfaceview

SurfaceView 的优点

  1. 使用双缓冲技术
  2. 自带画布,支持在子线程中更新画布内容

View 和 SurfaceView 各自使用场景

  1. 界面需要被动更新:使用View 。 画面更新是依赖于onTouch 来完成的,所以可以直接使用 invalidate() 函数。这种情况下,两次onTouch()间隔时间较长,不会产生影响
  2. 界面需要主动更新:使用SurfaceView。如一个动画需要一直移动或变化,这时需要一个单独的线程不停绘制人的状态,避免阻塞主线程。
  3. 界面需要频繁刷新,或刷新时数据处理量较大:使用SurfaceView。如视频播放、camera

SurfaceView继承于View,因此SurfaceView 可使用View中的所有方法,但::由于View中所有方法在主线程完成,当SurfaceView重写View的方法,那么也在主线程中完成。

总结:

  1. 原本能通过派生自View实现的控件,依然可以通过SurfaceView 实现,因为SurfaceView派生自View
  2. 当SurfaceView需要使用View的onDraw()来重绘控件时,需要在初始化的时候调用setWillNotDraw(false)【surfaceview默认为true,也就是不推荐这样】,否则onDraw()函数不会被调用
  3. View中的所有方法都在主线程中执行,不建议使用surfaceview重写view的onDraw()函数实现自定义控件,而使用surfaceview特有的双缓冲机制绘图。

https://blog.csdn.net/u013872857/article/details/91650236 多指画图。

 

使用缓存Canvas绘图:

SurfaceView 初衷为:绘图操作在子线程执行, 这样就不会占用主线程的资源。

 

监听Surface的生命周期:

SurfaceView相关的三个概念:Surface 、SurfaceView、SurfaceHolder,这三个概念为MVC模式(Model - View - Controller)。

  1. Model为数据层 对应 Surface :       保存着缓冲画布与绘图内容相关的各种信息。
  2. View为视图层   对应 SurfaceView:代表用户交互界面,负责将Surface中存储的数据展示在View上
  3. Controller 为控制器,对应 SurfaceHolder : Surface中是不允许直接用来操作的,必须通过SurfaceHolder来操作Surface中的数据。

由于canvas被保存在Surface中的,那么,必须Surface存在的时候,才能操作缓存Canvas,否则容易导致获取到的Canvas为空。因此我们可以在SurfaceHolder中添加对Surface生命周期的监听。

以下为监听的三个函数:

  1. SurfaceCreated() : 当Surface对象被创建后,该函数将立即被调用
  2. nSurfaceChange() : 当Surface发生任何结构性变化,该函数将立即被调用
  3. SurfaceDestroy() : 当Surface对象将要销毁时,该函数将立即被调用
  4. 通常       在SurfaceCrrated中开启线程来操作,防止Surface还未创建     ,    调用SurfaceDestroyed 看线程是否执行完,未执行完则强制取消。

 

双缓冲技术为至少两块画布,使用lockCanvas()时对画布进行操作,使用unlockCanvasAndPost()时替换画布,并开始呈现刚刚对画布的操作。

  1. lockCanvas() :                   用于获取整屏画布
  2. lockCanvas(Rect dirty):   用于获取指定区域的画布

surfaceView 如果默认为三块画布:

  1. 画布1展示 , 画布2,3缓冲, 此时画布1被清屏(全部绘制成黑色)
  2. 画布2与画布1换位子,画布2先复制画布1,再将自己的图形覆盖上去
  3. 画布3与画布2换位子,画布3先复制画布2,再将自己的图形覆盖上去

小总结:

  1. 缓冲画布是按照LRU(先进先出)策略被存取使用的
  2. 用holder.lockCanvas(rect) 获取到画布区域,再通过unlockCanvasAndPost(Canvas)函数提交到屏幕上, 指定区域内的内容为我们叠加(新的在上)绘制的结果,区域外是从当前屏幕复制过来的。
  3. 为防止区域内与区域外的图像所产生的内容有冲突,建议先清空画布。         只有我们将每块画布都画过以后,系统才会按照我们指定的区域来返回画布大小
  4. 如果不是区域绘制,仅仅是绘制数字那种,则不会复制前一块画布的内容,只展示自己画布的内容,因此出现1,3,5,7,9 而不是0,1,2,3,。。。。可以采用一个数组将其保存,然后每次画都逐个遍历

 

总结:

  1. 缓冲画布存取遵循LRU 策略
  2. lockCanvas() 获得整个画布,lockCanvas(dirt rect) 获取指定大小的缓冲画布
  3. 使用lockCanvas(rect) 函数获取缓冲画布前,需要使用while清屏                                                       画布未清空前,第一次拿到的画布将为整屏。
  4. 所获得画布以内的区域仍在原缓冲画布上叠加作画, 画布以外区域从屏幕上直接复制过来
  5. 由于画布以内的区域是原缓冲画布的基础上叠加作画,防止冲突,可使用Xfermode先清空所获得的的画布;或在内容不交叉时,采用增量绘制。

 

posted @ 2019-11-16 09:15  小#安  阅读(511)  评论(0编辑  收藏  举报