首页 > 编程知识 正文

surfaceview详解(surfaceview和view区别)

时间:2023-05-04 21:31:01 阅读:75063 作者:1356

背景中也有帧数高、要求实时性的动画。 传统的View刷新帧数不高,会出现纸箱现象,但表面视图可以解决此问题。

概念providesadedicateddrawingsurfaceembeddedinsideofaviewhierarchy.youcancontroltheformatofthissurfaceand,if you like,its size

SurfaceView是View的子类,该视图中嵌入了仅用于绘制的SurfaceView,允许您控制此Surface的大小和格式。 表面视图控制此表面的绘制位置。

thesurfaceiszorderedsothatitisbehindthewindowholdingitsurfaceview; thesurfaceviewpunchesaholeinitswindowtoallowitssurfacetobedisplayed.theviewhierarchywilltakecareofcorrectlycompositingwiththththed urfaceviewthatwouldnormallyappearontopofit.thiscanbeusedtoplaceoverlayssuchasbuttonsontopofthesurface thoughnotehoweverthatititite cesinceafullalpha-blendedcompositewillbeperformedeachtimethesurfacechanges transparentregionthatmakesthesurfacevisibleisbasbasededes iew hierarchy.ifthe post-layouttransformpropertion dtodrawasiblingviewontopofthesurfaceview,theviewmaynotbeproperlycomposier

surface是“深度排序”(Z-ordered ),表示它始终位于您所在窗口的后面。 “surfaceview”具有可见区域,只能看到该可见区域内的“surface”部分的内容,而不能看到可见区域外的部分。 表面合成的显示受视图级别关系的影响,同级视图节点显示在顶部。 这意味着surface的内容在同级视图中隐藏,该特性可用于放置“封面”(overlays ) (例如,文本和按钮等控件)。 请注意,如果表面上有透明控件,则每次更改时框架都会重新计算它和顶级控件的透明效果,从而影响性能。

accesstotheunderlyingsurfaceisprovidedviathesurfaceholderinterface,whichcanberetrievedbycallinggggetholder (。

可以通过SurfaceHolder界面访问此surface。 getHolder ()方法可以获得此接口。

thesurfacewillbecreatedforyouwhilethesurfaceview ' swindowisvisible; youshouldimplementsurfacecreated (表面支持者) andsurfacedestroyed (表面支持者) todiscoverwhenthesurfaceiscreatedanddder

当surfaceview显示时,将创建surface; 在surfaceview隐藏之前,surface将被销毁。 这样可以节约资源。 要确定何时创建和销毁surface,请重载surfacecreated(surfaceholder )和surface destroyed (surface holder )。

oneofthepurposesofthisclassistoprovideasurfac

e in which asecondary thread can render into the screen. If you are going to use it thisway, you need to be aware of some threading semantics:

surfaceview的核心在于提供了两个线程:UI线程和渲染线程。这里应注意

 

·        All SurfaceView and SurfaceHolder.Callback methods will be calledfrom the thread running the SurfaceView's window (typically the main thread ofthe application). They thus need to correctly synchronize with any state thatis also touched by the drawing thread.

所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。

 

·        You must ensure that the drawing thread only touches the underlyingSurface while it is valid -- between SurfaceHolder.Callback.surfaceCreated()and SurfaceHolder.Callback.surfaceDestroyed().

由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和

 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的

注意:

SurfaceView就是在Window挖了一个洞,他就是显示在这个洞里,其他的View是显示在Window上。

对于View执行绘制操作只能在UI线程上,绘制完成后需要调用View.Invalidate方法通知系统刷新View。而Surface是可以允许非UI线程绘制图像。

SurfaceView的生命周期

1,  打开Activity

surfaceCreated()->surfaceChanged()

2,点击back:

surfaceDestroyed()

3,点击Home键

surfaceDestroyed()

4,回到前台

surfaceChanged()->surfaceCreated()

5,屏幕锁定

不调用任何方法。

SurfaceView的使用

SurfaceView并不同于常规的View,对SurfaceView的控制是通过SurfaceHolder操作的。详细请看代码吧。

//继承SurfaceView并且实现CallBack方法

public class MySurfaceview extends SurfaceView implementsSurfaceHolder.Callback { private int distance; private int i; private int j; private final SurfaceHolder holder; public MySurfaceview(Context context){ super(context); holder = getHolder();//初始化的时候得到SurfaceHolder holder.addCallback(this);//设置接口。 };//当SurfaceView创建好的时候调用 @Override public voidsurfaceCreated(SurfaceHolder holder) { //进行绘制操作 } //当SurfaceView大小和格式改变的时候调用。 @Override public voidsurfaceChanged(SurfaceHolder holder, int format, int width, int height) { }//当SurfaceView销毁的时候调用 @Override public voidsurfaceDestroyed(SurfaceHolder holder) {//进行一些资源回收,和标志位的更新等操作。 } }
SurfaceView的绘制

      Surface在SurfaceHolder对象中,虽然Surface保存了当前窗口的像素数据,但是不能够直接操作Surface对象,而是通过SurfaceHolder的LockCavas()方法获得Canvas对象,通多对Canvas的操作来简介操作Surface。如果只修改Surface中部分内容,为了提高效率则只重回变化的部分可以调用lockCanvas(Rect dirty)方法,来绘制指定的区域,这样改区域外的内容会缓存起来。

       SurfaceView中的lockCanvas()和unlockCanvasAndPost(Canvascanvas)函数实现的同步锁机制,这样可以保证在Surface绘制过程中不会被改变。当绘制完成后调用unlockCanvasAndPost(Canvas canvas)函数,将内容显示出来。

       注意:lockCanvas()和unlockCanvasAndPost()方法是成对出现的,不能连续lockCanvas(),因为canvas已经被锁定,也不能连续unlockCanvasAndPost(),因为Canvas已经被提交,否则会抛出异常。

SurfaceView中的双缓冲机制

自己对双缓冲机制也不是十分明白,看了网上的说法不一,所以实践是检验真理的唯一标准,自己写了一下Demo进行了一下测试。

初始化SurfaceView之后,一次填充了白色,灰色,蓝色。

//填充白色

public void fillWhiteColor() { Canvas canvas =holder.lockCanvas(); canvas.drawColor(Color.WHITE); holder.unlockCanvasAndPost(canvas); }


//填充灰色
   

public void fillGrayColor() { Canvas canvas =holder.lockCanvas(); canvas.drawColor(Color.GRAY); holder.unlockCanvasAndPost(canvas); }


//填充蓝色
  

public void fillBlueColor() { Canvas canvas =holder.lockCanvas(); canvas.drawColor(Color.BLUE); holder.unlockCanvasAndPost(canvas); }


而之后多次就绘制数字到屏幕上。会出现一下现象。

白色背景出现的数字为:3,6,9,12...

灰色背景出现的数字为:1,4,7,10…

蓝色背景上出现的数字为:2,5,8,11…

 

 

测试手机为nexus5。

结论:这是surfaceView的缓冲机制造成的,而在Android4.1之后会引入三缓冲机制,使用lockCanvas(),方法获取到的是三个画布轮流切换,在Android4.1之前默认是两个,而之后默认是三个,厂商可以根据需求自己定制,但是最多可以使用32个缓冲区。

 //关键代码如下:

public class MySurfaceview extends SurfaceView implementsSurfaceHolder.Callback { private int distance; private int i; private int j; private final SurfaceHolder holder; public MySurfaceview(Context context){ super(context); holder = getHolder(); holder.addCallback(this); } @Override public voidsurfaceCreated(SurfaceHolder holder) { } @Override public void surfaceChanged(SurfaceHolderholder, int format, int width, int height) { } @Override public voidsurfaceDestroyed(SurfaceHolder holder) { } public void draw() { Paint paint = new Paint(); paint.setTextSize(30); paint.setColor(Color.RED); Canvas canvas =holder.lockCanvas(); canvas.drawText(String.valueOf(i), getWidth() / 2, distance, paint); i++; distance = distance + 40; holder.unlockCanvasAndPost(canvas); } public void fillWhiteColor() { Canvas canvas =holder.lockCanvas(); canvas.drawColor(Color.WHITE); holder.unlockCanvasAndPost(canvas); } public void fillGrayColor() { Canvas canvas =holder.lockCanvas(); canvas.drawColor(Color.GRAY); holder.unlockCanvasAndPost(canvas); } public void fillBlueColor() { Canvas canvas =holder.lockCanvas(); canvas.drawColor(Color.BLUE); holder.unlockCanvasAndPost(canvas); } public void lockRect() { Paint paint = new Paint(); paint.setTextSize(30); j++; Canvas canvas =holder.lockCanvas(new Rect(getWidth() / 2 - 60, 0, getWidth() / 2 - 30,getHeight())); canvas.drawText(String.valueOf(j), getWidth() / 2 - 45, getHeight() / 2,paint); holder.unlockCanvasAndPost(canvas); }}
解决方案

 

一般游戏里说的双缓冲防止画面闪烁,只是每一帧先绘制到bitmap再绘制到SurfaceView的canvas。

LockCanvas(Rect dirty)

由于surfaceview是多缓冲机制,所以lockCanvas(Rect)是修改rect内的内容。而调用lockCanvas(rect)方法会把当前页的内容填充到下一个缓冲区。有demo自己可以测试。

 

遗留问题

进入到surfaceview页面,画的第一个背景不能填充到缓冲区,不知道为什么,知道的同学们可以留个言,谢谢大家。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。