Android SurfaceView

摘要:
引伸地,可以认为Android中的Surface就是一个用来画图形或图像的涂鸦场所。结合SurfaceView与Surface的关系,可得知整个屏幕都是经过了Surface的绘制,而SurfaceView则提供了手动绘制指定区域的机会。它能够感知Surface的存在,并对Surface进行操作。所得到的Canvas对象,其实就是Surface中一个成员。SurfaceHolder.Callback主要是当底层的Surface被创建、销毁或者改变时提供回调通知。

一、SurfaceView简介
SurfaceView可以在主线程之外的线程中向屏幕绘图上。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。在游戏开发中多用到SurfaceView,游戏中的背景、人物、动画等等尽量在画布canvas中画出。
什么是Surface
在这里要先说说什么是Surface。简单的说Surface对应了一块屏幕缓冲区,每个window对应一个Surface,任何View都要画在Surface的Canvas(画布)上。传统的view共享一块屏幕缓冲区,所有的绘制必须在UI线程中进行。
在SDK的文档中,对Surface的描述是这样的:“Handle onto a raw buffer that is being managed by the screen compositor”,翻译成中文就是“由屏幕显示内容合成器(screen compositor)所管理的原始缓冲区的句柄”,这句话包括下面两个意思:
1、通过Surface就可以获得原生缓冲器以及其中的内容(因为Surface是句柄)。就像在C++语言中,可以通过一个文件的句柄,就可以获得文件的内容一样。
2、原始缓冲区(a raw buffer)是用于保存当前窗口的像素数据的。引伸地,可以认为Android中的Surface就是一个用来画图形(graphics)或图像(image)的涂鸦场所。由此,可以推知一个Surface对象中应该包含有一个Canvas(画布)对象。
因此,在前面提及的两个意思的基础上,可以再加上一条:
3、Surface中有一个Canvas成员,专门用于画图的。
由以上的概括,我们总结如下:Surface中的Canvas成员,是专门用于供程序员画图的场所,就像黑板一样;其中的原始缓冲区是用来保存数据的地方;Surface本身的作用类似一个句柄,得到了这个句柄就可以得到其中的Canvas、原始缓冲区以及其它方面的内容。
Surface是用来管理数据的(句柄),在这里“数据”指的就是画板的内容。
什么是SurfaceView
说SurfaceView是一个View也许不够严谨,然而从定义中pubilc classSurfaceView extends View{.....}显示SurfaceView确实是派生自View,但是SurfaceView却有自己的Surface,看SurfaceView的一部分源码,大家感受一下:

 if (mWindow == null) {      
             mWindow = new MyWindow(this);      
             mLayout.type =mWindowType;      
             mLayout.gravity = Gravity.LEFT|Gravity.TOP;      
             mSession.addWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,      
             mVisible ?VISIBLE : GONE, mContentInsets);       
       }    

很明显,每个SurfaceView创建的时候都会创建一个MyWindow,new MyWindow(this)中的this正是SurfaceView自身,因此将SurfaceView和window绑定在一起,由第一部分我们知道,一个window对应一个Surface,SurfaceView就是展示Surface中数据的地方,同时可以认为SurfaceView是用来控制Surface中View的位置和尺寸的(也就是说,SurfaceView可以控制Surface中的内容)。
大家都知道,传统View及其派生类的更新只能在UI线程,然而UI线程还同时处理其他交互逻辑,这就无法保证View更新的速度和帧率了,而SurfaceView可以用独立的线程进行绘制,因此可以提供更高的帧率,例如游戏,摄像头取景等场景就比较适合SurfaceView来实现。
结合 SurfaceView 与 Surface 的关系,可得知整个屏幕都是经过了 Surface 的绘制,而 SurfaceView 则提供了手动绘制指定区域的机会。
下图为 SurfaceView 与 Surface 的关系。
Android SurfaceView第1张
二、相关类
SurfaceHolder
SurfaceHolder是一个接口,其作用是一个关于Surface的监听器,提供访问和控制 SurfaceView 内嵌的 Surface 相关的方法。它能够感知 Surface 的存在,并对 Surface 进行操作。
在SurfaceView中有一个方法 getHolder() ,可以很方便地获得SurfaceView所对应的Surface所对应的 SurfaceHolder。
除了接下来将提到的 Callback 外, SurfaceHolder 还提供了几个很重要的方法:
1、abstract void addCallback(SurfaceHolder.Callbackcallback):为SurfaceHolder添加一个SurfaceHolder.Callback回调接口,此方法下面将会提到。
2、abstract Canvas lockCanvas():获取一个Canvas对象,并锁定之。所得到的Canvas对象,其实就是Surface中一个成员。
3、abstract Canvas lockCanvas(Rect dirty):同上。但只锁定dirty所指定的矩形区域,因此效率更高。
4、abstract void unlockCanvasAndPost(Canvas canvas):当修改Surface中的数据完成后,释放同步锁,并提交改变,然后将新的数据进行展示,同时Surface中相关数据会被丢失。
2、3、4中的同步锁机制的目的,就是为了在绘制的过程中,Surface中的数据不会被改变。lockCanvas是为了防止同一时刻多个线程对同一canvas写入。因此要特别注意,只有当 unlockCanvasAndPost 之后,才能再获取 Canvas。
SurfaceHolder.Callback
SurfaceHolder.Callback接口可以感知到Surface的创建、销毁或者改变。
SurfaceHolder.Callback主要是当底层的Surface被创建、销毁或者改变时提供回调通知。我们知道,对画布绘制必须在Surface被创建后才能进行,因此SurfaceHolder.Callback中的surfaceCreated 和surfaceDestroyed 这两个方法就成了绘图处理代码的边界。
要实现该接口,只需要在 SurfaceHolder 中调用 addCallback() 方法即可。
SurfaceHolder.Callback中定义了三个接口方法:

@Override  
        public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, intarg3)   
        {  
            //当surface发生任何结构性的变化时(格式或者大小),该方法就会被立即调用。  
}  
      
        @Override  
        public voidsurfaceCreated(SurfaceHolder holder)   
        {  
            //当surface对象创建后,该方法就会被立即调用。  
}  
      
        @Override  
        public voidsurfaceDestroyed(SurfaceHolder holder)  
        {  
            //当surface对象在将要销毁前,该方法会被立即调用。  
}  

Canvas
Canvas 对象,可以把它当做画布,Canvas 的方法大多数是设置画布的大小、形状、画布背景颜色等等,要想在画布上面画画,一般要与 Paint对象结合使用Paint就是画笔的风格,颜料的色彩之类的。
当然了,你也可以在上面花图片,这些都是通过调用 drawXXX() 来实现的。

    //创建画笔       
    Paint paint = newPaint();    
    //设置红色         
paint.setColor(Color.RED);  
     //画一个圆     
    canvas.drawCircle(60, 20, 10, paint); 

免责声明:文章转载自《Android SurfaceView》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【转】可在广域网部署运行的即时通讯系统 -- GGTalk总览(附源码下载)SSH认证原理和批量分发管理下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Canvas坐标系转换

默认坐标系与当前坐标系 canvas中的坐标是从左上角开始的,x轴沿着水平方向(按像素)向右延伸,y轴沿垂直方向向下延伸。左上角坐标为x=0,y=0的点称作原点。在默认坐标系中,每一个点的坐标都是直接映射到一个CSS像素上。 但是如果图像的每次绘制都参考一个固定点将缺少灵活性,于是在canvas中引入“当前坐标系”的概念,所谓“当前坐标系”即指图像在此时...

深入理解读写锁—ReadWriteLock源码分析

转载:https://blog.csdn.net/qq_19431333/article/details/70568478 ReadWriteLock管理一组锁,一个是只读的锁,一个是写锁。读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的。 所有读写锁的实现必须确保写操作对读操作的内存影响。换句话说,一个获得了读锁的线程必须能看到前一个释放的写锁所...

Android+Camera+SurfaceView自定义相机系列(一)

本文主要介绍如何使用camera+surfaceview来自定义相机,我们使用自定义相机进行拍照、扫描二维码等等。Camera是属于硬件部分,在开发中会经常遇到如何使用相机。在上一篇文章中介绍了如何动态的申请权限,使用相机是需要动态申请权限的。 根据官方文档介绍在拍摄照片时,用户通常要先看到拍摄目标的预览效果,然后再按下快门。为此,您可以使用Surface...

Qt 学习之路 2(75):线程总结

前面我们已经详细介绍过有关线程的一些值得注意的事项。现在我们开始对线程做一些总结。 有关线程,你可以做的是: 在QThread子类添加信号。这是绝对安全的,并且也是正确的(前面我们已经详细介绍过,发送者的线程依附性没有关系) 不应该做的是: 调用moveToThread(this)函数 指定连接类型:这通常意味着你正在做错误的事情,比如将QThread控...

一、从Windows消息机制说起

    一,消息       消息(Message)指的就是Windows 操作系统发给应用程序的一个通知,它告诉应用程序某个特定的事件发生了。比如,用户单击鼠标或按键都会引发Windows 系统发送相应的消息。最终处理消息的是应用程序的窗口函数,如果程序没处理的话操作系统有默认函数将会作出处理。     从数据结构的角度来说,消息是一个结构体,它包含了...

并发编程-线程池(二)线程池回收线程

【1】https://blog.csdn.net/u013256816/article/details/109213183   面试 鹅厂 的时候,问到了 线程池如何销毁线程,这题答的不好。   这个问题考察的是对线程池的理解,在既然了解了线程池在什么时候创建线程。   那么也要了解线程池在不同情况是如何回收线程,什么时候回收,怎么回收。 一、线程池状态和...