首页 > 代码库 > Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系

Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系

转载请包括网址:http://blog.csdn.net/pathuang68/article/details/7351317

一、Surface

Surface就是“表面”的意思。在SDK的文档中,对Surface的描写叙述是这种:“Handle onto a raw buffer that is being managed by the screen compositor”,翻译成中文就是“由屏幕显示内容合成器(screen compositor)所管理的原生缓冲器的句柄”,这句话包含以下两个意思:

1.      通过Surface(由于Surface是句柄)就能够获得原生缓冲器以及当中的内容。就像在C语言中,能够通过一个文件的句柄,就能够获得文件的内容一样;

2.      原生缓冲器(rawbuffer)是用于保存当前窗体的像素数据的。

引伸地,能够觉得Android中的Surface就是一个用来绘图形(graphics)或图像(image)的地方。依据Java方面的常规知识,我们知道通常绘图是在一个Canvas对象上面进行的,由此,能够推知一个Surface对象中应该包括有一个Canvas对象,其实的确如此,并且这一点能够非常easy通过debug执行程序的方式得到证明(将光标停留在对象变量surface上,会弹出一个对话框,当中红色方框的内容,就表面surface中有一个CompatileCanvas成员变量)当然,看源码也是能够证明这一点:


因此,在前面提及的两个意思的基础上,能够再加上一条:

3.      Surface中有一个Canvas成员,专门用于绘图的。

所以,Surface中的Canvas成员,是专门用于供程序猿绘图的场所,就像黑板一样;当中的原生缓冲器是用来保存数据的地方;Surface本身的作用类似一个句柄,得到了这个句柄就能够得到当中的Canvas、原生缓冲器以及其他方面的内容。

 

二、SurfaceView

SurfaceView,顾名思义就是Surface的View,通过SurfaceView就能够看到Surface的部分或者所有的内容,以下用一个图来形象地描写叙述一下Surface和SurfaceView的关系:


也就是说,Surface是用通过SurfaceView才干展示当中的内容。从这个意思上来说,SurfaceView中的View之确切的含义应该是viewport即“视口”的意思,做过数据库设计的朋友知道,假定一个数据表有20个字段,但我们经常仅仅用到当中的5个字段,那么就能够在原数据表的基础上,通过SQL语句CREATEVIEW来创建仅仅包括那5个字段内容的view。

还有一方面,SurfaceView是Android中View的子类。其实,在Android中全部用于界面展示的类皆为View的子类,包含那些不可见的、各种各样的Layout。

所以说,SurfaceView中的View有两个含义:

1.      视口(viewport)的意思

2.      SurfaceView是View的派生类

 

在Android中Surface是从Object派生而来,且实现了Parcelable接口。看到Parcelable就让人能非常自然地想到数据容器,SurfaceView就是用来展示Surface中的数据的。在这个层面上而言,Surface就是管理数据的地方,SurfaceView就是展示数据的地方。

 

三、SurfaceHolder

SurfaceHolder是一个接口,其作用就像一个关于Surface的监听器。提供訪问和控制SurfaceView背后的Surface 相关的方法 (providingaccess and control over this SurfaceView‘s underlying surface),它通过三个回调方法,让我们能够感知到Surface的创建、销毁或者改变。在SurfaceView中有一个方法getHolder,能够非常方便地获得SurfaceView所相应的Surface所相应的SurfaceHolder(有点拗口吧)。

 

除以下将要提到的SurfaceHolder.Callback外,SurfaceHolder还提供了非常多重要的方法,当中最重要的就是:

1.        abstract void addCallback(SurfaceHolder.Callbackcallback)

为SurfaceHolder加入?一个SurfaceHolder.Callback回调接口。

2.        abstract Canvas lockCanvas()

获取一个Canvas对象,并锁定之。所得到的Canvas对象,事实上就是Surface中一个成员。

3.        abstract Canvas lockCanvas(Rectdirty)

同上。但仅仅锁定dirty所指定的矩形区域,因此效率更高。

4.        abstract void unlockCanvasAndPost(Canvascanvas)

当改动Surface中的数据完毕后,释放同步锁,并提交改变,然后将新的数据进行展示,同一时候Surface中相关数据会被丢失。

5.      public abstract void setType (int type)

         设置Surface的类型,接收例如以下的參数:

SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface

SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface

SURFACE_TYPE_GPU:适用于GPU加速的Surface

SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包括原生数据,Surface用到的数据由其它对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比較流畅。假设设置这样的类型则就不能调用lockCanvas来获取Canvas对象了。须要注意的是,在高版本号的Android SDK中,setType这种方法已经被depreciated了。

2、3、4中的同步锁机制的目的,就是为了在绘制的过程中,Surface中的数据不会被改变。


从设计模式的高度来看,Surface、SurfaceView和SurfaceHolder实质上就是广为人知的MVC,即Model-View-Controller。Model就是模型的意思,或者说是数据模型,或者更简单地说就是数据,也就是这里的Surface;View即视图,代表用户交互界面,也就是这里的SurfaceView;SurfaceHolder非常明显能够理解为MVC中的Controller(控制器)。这样看起来三者之间的关系就清楚了非常多。

 

四、SurfaceHolder.Callback

前面已经讲到SurfaceHolder是一个接口,它通过回到方法的方式,让我们能够感知到Surface的创建、销毁或者改变。事实上这一点是通过其内部的静态子接口SurfaceHolder.Callback来实现的。SurfaceHolder.Callback中定义了三个接口方法:

1.     abstract void surfaceChanged(SurfaceHolderholder, int format, int width, int height)

当surface发生不论什么结构性的变化时(格式或者大小),该方法就会被马上调用。

2.      abstract void surfaceCreated(SurfaceHolderholder)

当surface对象创建后,该方法就会被马上调用。

3.      abstract void surfaceDestroyed(SurfaceHolderholder)

当surface对象在将要销毁前,该方法会被马上调用。

 

在Android SDK文档中,关于SurfaceView的描写叙述里面,有一段这种话:

One of the purposes of this class is to provide a surface in which a secondarythread can render into the screen. If you are going to use it this way, youneed to be aware of some threading semantics:

 

-        All SurfaceView and SurfaceHolder.Callbackmethods will be called from the thread running the SurfaceView‘s window(typically the main thread of the application). They thus need to correctlysynchronize with any state that is also touched by the drawing thread.

-      You must ensure that the drawingthread only touches the underlying Surface while it is valid -- betweenSurfaceHolder.Callback.surfaceCreated() andSurfaceHolder.Callback.surfaceDestroyed().

这段话非常重要,大致意思例如以下:

这个类的目的之中的一个,就是提供一个能够用另外一个线程(第二个线程)进行屏幕渲染的surface(译注:即UI线程和绘制线程能够分离)。假设你打算这样使用,那么应当注意一些线程方面的语义:

-           全部SurfaceView和SurfaceHolder.Callback中声明的方法,必须在执行SurfaceView窗体中的线程中调用(典型地,就是应用的主线程。译注:即UI线程),由于它们须要正确地将同一时候被绘制线程訪问的各种状态进行同步。

-           必须保证,仅仅有在背后的Surface有效的时候 – 在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()这两个方法调用之间,訪问它。

 

以下,我们通过一个很easy样例来实际感受一下(代码摘自http://www.cnblogs.com/xuling/archive/2011/06/06/android.html,并做了一些结构性的修改),请留意代码中的凝视:

1.        在Eclipse中创建一个Android Project项目TestSurfaceView,并选择生成缺省的Activity TestSurfaceViewActivity

2.        创建一个绘制线程例如以下:


package com.pat.testsurfaceview;
 
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
importandroid.view.SurfaceHolder;
 
// 绘制线程
public class MyThread extendsThread
{
         private SurfaceHolder holder;
         private boolean run;
        
         public MyThread(SurfaceHolder holder)
         {
                   this.holder = holder;
                   run = true;
         }
 
         @Override
         public void run()
         {
                   int counter = 0;
                   Canvas canvas = null;
                   while(run)
                   {
                            // 详细绘制工作
                            try
                            {
                                     // 获取Canvas对象,并锁定之
                                     canvas= holder.lockCanvas();
                                    
                                     // 设定Canvas对象的背景颜色
                                     canvas.drawColor(Color.WHITE);
                                    
                                     // 创建画笔
                                     Paintp = new Paint();
                                     // 设置画笔颜色
                                     p.setColor(Color.BLACK);
                                     // 设置文字大小
                                     p.setTextSize(30);
                                    
                                     // 创建一个Rect对象rect
                                     Rect rect = new Rect(100, 50, 380, 330);
                                     // 在canvas上绘制rect
                                     canvas.drawRect(rect,p);
                                     // 在canvas上显示时间
                                     canvas.drawText("Interval = " + (counter++) + " seconds.", 100, 410, p);
                                     Thread.sleep(1000);
                            }
                            catch(Exception e)
                            {
                                     e.printStackTrace();
                            }
                            finally
                            {
                                     if(canvas != null)
                                     {
                                               // 解除锁定,并提交改动内容
                                               holder.unlockCanvasAndPost(canvas);
                                     }
                            }
                   }
         }
 
         public boolean isRun()
         {
                   return run;
         }
        
         public void setRun(boolean run)
         {
                   this.run = run;
         }
}

3.      自己定义一个SurfaceView类例如以下:


package com.pat.testsurfaceview;
 
import android.content.Context;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
 
public class MySurfaceView extends SurfaceView
implements
SurfaceHolder.Callback
{
         private SurfaceHolder holder;
         private MyThread myThread;
        
         publicMySurfaceView(Context context)
         {
                   super(context);
                  
                   // 通过SurfaceView获得SurfaceHolder对象
                   holder = getHolder();
                  
                   // 为holder加入?回调结构SurfaceHolder.Callback
                   holder.addCallback(this);
                  
                   // 创建一个绘制线程,将holder对象作为參数传入,这样在绘制线程中就能够获得holder
                   // 对象,进而在绘制线程中能够通过holder对象获得Canvas对象,并在Canvas上进行绘制
                   myThread = new MyThread(holder);
         }
 
         // 实现SurfaceHolder.Callback接口中的三个方法,都是在主线程中调用,而不是在绘制线程中调用的
         @Override
         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
         {
         }
 
         @Override
         public void surfaceCreated(SurfaceHolder holder)
         {
                   // 启动线程。当这种方法调用时,说明Surface已经有效了
                   myThread.setRun(true);
                   myThread.start();
         }
 
         @Override
         public void surfaceDestroyed(SurfaceHolderholder)
         {
                   // 结束线程。当这种方法调用时,说明Surface即将要被销毁了
                   myThread.setRun(false);
         }
}
 

4.    改动TestSurfaceViewActivity.java代码,使之例如以下:


package com.pat.testsurfaceview;
 
import android.app.Activity;
import android.os.Bundle;
 
public class TestSurfaceViewActivity extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.main);
        setContentView(new MySurfaceView(this));
    }
}
 

执行结果:

 

非常显然,我们能够在MyThread的run方法中,做非常多更有意思的事情。弄清楚了Surface、SurfaceView、SurfaceHolder和SurfaceHolder.Callback这些概念,以及它们之间的关系,对我们更好地使用它们应该会有相当大的帮助。

Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系